Интро


Столкнулся с тем, что youtube.com «забывает» видео, которые я просмотрел.
Приходится смотреть много образовательных каналов, а потом вспоминать, видел я это или нет.
Посмотрел какую-нибудь лекцию и через несколько дней (месяцев, лет) статус "просмотрено" пропадает.
Или, наоборот, посмотришь 2 минуты какой-нибудь лекции, ляжешь спать, а на утро лекция имеет статус «просмотрено».

Вот и решил взять под контроль информацию о просмотрах на youtube в свои руки.
И хранить эту информацию вне зависимости от ютюба.
Если у кого-нибудь есть нужда в такого рода запоминании просмотров, то добро пожаловать под кат.

Скриншоты


Иногда скриншоты лучше объясняют, чем сама статья.
Поэтому привожу их в первую очередь:


Можно добавить каналы, которые вам интересны.





Реализация на любом языке веб-программирования


Итак, пишем свой youtube с возможностью запоминания просмотров и с прекрасными лекторшами.
«Наш ютюб» будет получать информацию от google API и будет своего рода прослойкой между вами и ютюбом.
И будет хранить информацию о просмотрах в нашей базе данных.

Я написал это на python и фреймворке flask, получилось 70 строк, ссылка на гитхаб внизу статьи.
Но так как это можно воссоздать и на php, и на perl и на других языках для веб, то сначала общие принципы…

Работа с google API


Получить ключ google API к youtube. Можно здесь.

Информация о канале
Для создания сайта нам понадобится получать информацию о канале.
Возьмем для примера вот такую ссылку:
www.youtube.com/channel/UC640y4UvDAlya_WOj5U4pfA
UC640y4UvDAlya_WOj5U4pfA — это ID канала.
Обращаемся к API:

curl 'https://www.googleapis.com/youtube/v3/channels?part=snippet&id=UC640y4UvDAlya_WOj5U4pfA&key=ВАШ_КЛЮЧ_API'

И получаем вот такой ответ в формате JSON
{
 "kind": "youtube#channelListResponse",
 "etag": "\"kYnGHzMaBhcGeLrcKRx6PAIUosY/YqjVAeQ4_JORc2ijoBKla3hrDXE\"",
 "pageInfo": {
  "totalResults": 1,
  "resultsPerPage": 1
 },
 "items": [
  {
   "kind": "youtube#channel",
   "etag": "\"kYnGHzMaBhcGeLrcKRx6PAIUosY/OE6leaeClJlkthEEiPP5KVJQZPQ\"",
   "id": "UC640y4UvDAlya_WOj5U4pfA",
   "snippet": {
    "title": "nptelhrd",
    "description": "Your favorite courses available for certification! study, write an exam and get a certificate from the IITs! Check http://nptel.ac.in/noc\n\nThis channel provides technical lectures from seven Indian Institutes of Technology (IITs) and Indian Institute of Science (IISc) Bangalore.\n\nPlease visit the NPTEL Channel List below to view the complete list of courses. (24 Channels)",
    "publishedAt": "2007-11-28T04:54:13.000Z",
    "thumbnails": {
     "default": {
      "url": "https://yt3.ggpht.com/-VO_A5Tys4WY/AAAAAAAAAAI/AAAAAAAAAAA/mBvvbUvh0A8/s88-c-k-no/photo.jpg"
     },
     "medium": {
      "url": "https://yt3.ggpht.com/-VO_A5Tys4WY/AAAAAAAAAAI/AAAAAAAAAAA/mBvvbUvh0A8/s240-c-k-no/photo.jpg"
     },
     "high": {
      "url": "https://yt3.ggpht.com/-VO_A5Tys4WY/AAAAAAAAAAI/AAAAAAAAAAA/mBvvbUvh0A8/s240-c-k-no/photo.jpg"
     }
    },
    "localized": {
     "title": "nptelhrd",
     "description": "Your favorite courses available for certification! study, write an exam and get a certificate from the IITs! Check http://nptel.ac.in/noc\n\nThis channel provides technical lectures from seven Indian Institutes of Technology (IITs) and Indian Institute of Science (IISc) Bangalore.\n\nPlease visit the NPTEL Channel List below to view the complete list of courses. (24 Channels)"
    }
   }
  }
 ]
}



Отсюда можно дернуть поле 'title' и использовать как название канала.

Получаем список видео с канала
curl 'https://www.googleapis.com/youtube/v3/search?part=snippet&channelId=UCEBb1b_L6zDS3xTUrIALZOw&order=date&key=ВАШ_КЛЮЧ_API'


И получаем вот такой ответ в формате JSON
{
 "kind": "youtube#searchListResponse",
 "etag": "\"kYnGHzMaBhcGeLrcKRx6PAIUosY/vGlosUUKRoHE50sX08btNSJuUT0\"",
 "nextPageToken": "CAUQAA",
 "pageInfo": {
  "totalResults": 3493,
  "resultsPerPage": 5
 },
 "items": [
  {
   "kind": "youtube#searchResult",
   "etag": "\"kYnGHzMaBhcGeLrcKRx6PAIUosY/f-Aj24y6ay5s_ofPTa82fwx3hP0\"",
   "id": {
    "kind": "youtube#video",
    "videoId": "NtMOab_nhs0"
   },
   "snippet": {
    "publishedAt": "2015-04-02T00:35:45.000Z",
    "channelId": "UCEBb1b_L6zDS3xTUrIALZOw",
    "title": "Octave/MATLAB® for Beginners, Part 2: Fitting Data and Plotting",
    "description": "MIT 22.15 Essential Numerical Methods, Fall 2014 View the complete course: http://ocw.mit.edu/22-15F14 Instructor: Ian Hutchinson Plotting the line that results ...",
    "thumbnails": {
     "default": {
      "url": "https://i.ytimg.com/vi/NtMOab_nhs0/default.jpg"
     },
     "medium": {
      "url": "https://i.ytimg.com/vi/NtMOab_nhs0/mqdefault.jpg"
     },
     "high": {
      "url": "https://i.ytimg.com/vi/NtMOab_nhs0/hqdefault.jpg"
     }
    },
    "channelTitle": "MIT",
    "liveBroadcastContent": "none"
   }
  },
  {
   "kind": "youtube#searchResult",
   "etag": "\"kYnGHzMaBhcGeLrcKRx6PAIUosY/qLJGwF303RMmdl03IbivB2VkIQ4\"",
   "id": {
    "kind": "youtube#video",
    "videoId": "WUxImdA7k8E"
   },
   "snippet": {
    "publishedAt": "2015-04-02T00:35:45.000Z",
    "channelId": "UCEBb1b_L6zDS3xTUrIALZOw",
    "title": "Octave/MATLAB® for Beginners, Part 3: Cleaning Up & Saving Plots",
    "description": "MIT 22.15 Essential Numerical Methods, Fall 2014 View the complete course: http://ocw.mit.edu/22-15F14 Instructor: Ian Hutchinson Cleaning up and saving ...",
    "thumbnails": {
     "default": {
      "url": "https://i.ytimg.com/vi/WUxImdA7k8E/default.jpg"
     },
     "medium": {
      "url": "https://i.ytimg.com/vi/WUxImdA7k8E/mqdefault.jpg"
     },
     "high": {
      "url": "https://i.ytimg.com/vi/WUxImdA7k8E/hqdefault.jpg"
     }
    },
    "channelTitle": "MIT",
    "liveBroadcastContent": "none"
   }
  },
  {
   "kind": "youtube#searchResult",
   "etag": "\"kYnGHzMaBhcGeLrcKRx6PAIUosY/mKjnuWcbJIZE_fKn12kg7B-lrN0\"",
   "id": {
    "kind": "youtube#video",
    "videoId": "LhPZwdhutgU"
   },
   "snippet": {
    "publishedAt": "2015-04-02T00:35:45.000Z",
    "channelId": "UCEBb1b_L6zDS3xTUrIALZOw",
    "title": "Octave/MATLAB® for Beginners, Part 1: Starting from Scratch",
    "description": "MIT 22.15 Essential Numerical Methods, Fall 2014 View the complete course: http://ocw.mit.edu/22-15F14 Instructor: Ian Hutchinson Create adjacent windows ...",
    "thumbnails": {
     "default": {
      "url": "https://i.ytimg.com/vi/LhPZwdhutgU/default.jpg"
     },
     "medium": {
      "url": "https://i.ytimg.com/vi/LhPZwdhutgU/mqdefault.jpg"
     },
     "high": {
      "url": "https://i.ytimg.com/vi/LhPZwdhutgU/hqdefault.jpg"
     }
    },
    "channelTitle": "MIT",
    "liveBroadcastContent": "none"
   }
  },
  {
   "kind": "youtube#searchResult",
   "etag": "\"kYnGHzMaBhcGeLrcKRx6PAIUosY/EteK6EKK5CG4IAAX3JjzWUD0oAQ\"",
   "id": {
    "kind": "youtube#playlist",
    "playlistId": "PLUl4u3cNGP63_OOz8w5qDEoqErZ8Hj-fc"
   },
   "snippet": {
    "publishedAt": "2015-04-02T00:34:03.000Z",
    "channelId": "UCEBb1b_L6zDS3xTUrIALZOw",
    "title": "MIT 22.15 Essential Numerical Methods, Fall 2014",
    "description": "View the complete course: http://ocw.mit.edu/22-15F14 Instructor: Ian Hutchinson Three short tutorial videos which demonstrate basic operation of Octave software, used in this graduate-level...",
    "thumbnails": {
     "default": {
      "url": "https://i.ytimg.com/vi/LhPZwdhutgU/default.jpg"
     },
     "medium": {
      "url": "https://i.ytimg.com/vi/LhPZwdhutgU/mqdefault.jpg"
     },
     "high": {
      "url": "https://i.ytimg.com/vi/LhPZwdhutgU/hqdefault.jpg"
     }
    },
    "channelTitle": "MIT",
    "liveBroadcastContent": "none"
   }
  },
  {
   "kind": "youtube#searchResult",
   "etag": "\"kYnGHzMaBhcGeLrcKRx6PAIUosY/jI4Bwr7emgpt45cnFetFPewI7qU\"",
   "id": {
    "kind": "youtube#playlist",
    "playlistId": "PLUl4u3cNGP62FPGcyFJkzhqq9c5cHCK32"
   },
   "snippet": {
    "publishedAt": "2015-03-23T21:38:55.000Z",
    "channelId": "UCEBb1b_L6zDS3xTUrIALZOw",
    "title": "MIT 8.421 Atomic and Optical Physics I, Spring 2014",
    "description": "MIT 8.421 Atomic and Optical Physics I, Spring 2014 View the complete course: http://ocw.mit.edu/8-421S14 Instructor: Wolfgang Ketterle This is the first of a ...",
    "thumbnails": {
     "default": {
      "url": "https://i.ytimg.com/vi/iwQ49oG-DO8/default.jpg"
     },
     "medium": {
      "url": "https://i.ytimg.com/vi/iwQ49oG-DO8/mqdefault.jpg"
     },
     "high": {
      "url": "https://i.ytimg.com/vi/iwQ49oG-DO8/hqdefault.jpg"
     }
    },
    "channelTitle": "MIT",
    "liveBroadcastContent": "none"
   }
  }
 ]
}


По умолчанию он будет выводить за один раз 5 последних видео с канала.
Чтобы это изменить, можно добавить параметр &maxResults=10, например.
Для навигации по страницам канала в JSON выдаются следующие значения:
«nextPageToken» и «prevPageToken».
Если нужно перейти на следующую или предыдущую страницу, то вводим дополнительный параметр &pageToken=
и подставляем сюда значение «nextPageToken» или «prevPageToken».

Информация об отдельно взятом видео
Вообще я этот запрос не использовал в своем сайте, но может пригодиться.
Поэтому привожу его:
curl 'https://ww.googleapis.com/youtube/v3/videos?part=snippet&id=EhNWzcUwqGbI&key=ВАШ_КЛЮЧ_API'


И получаем вот такой ответ в формате JSON
{
 "kind": "youtube#videoListResponse",
 "etag": "\"IHLB7Mi__JPvvG2zLQWAg8l36UU/2kAxpYyny-CEVVbQ2cOjO-XSscQ\"",
 "pageInfo": {
  "totalResults": 1,
  "resultsPerPage": 1
 },
 "items": [
  {
   "kind": "youtube#video",
   "etag": "\"IHLB7Mi__JPvvG2zLQWAg8l36UU/vAIAewyN9KKpNPERU4b4tOjuPL4\"",
   "id": "EhNWzcUqGbI",
   "snippet": {
    "publishedAt": "2013-03-16T06:58:52.000Z",
    "channelId": "UCuLLf8HBxpa-RV1sf9CRmDg",
    "title": "50 MPH 52v Electric Mountain Bike",
    "description": "http://voltbicycles.com This is our Alite 1000 Electric Mountain bike powered by a black lighting brushless rear hub electric motor with a 52v battery system. This electric bike will do around 50 MPH and will run 30+ miles on a single charge. \n\nGOING GREEN DOESN'T HAVE TO BE BORING",
    "thumbnails": {
     "default": {
      "url": "https://i.ytimg.com/vi/EhNWzcUqGbI/default.jpg",
      "width": 120,
      "height": 90
     },
     "medium": {
      "url": "https://i.ytimg.com/vi/EhNWzcUqGbI/mqdefault.jpg",
      "width": 320,
      "height": 180
     },
     "high": {
      "url": "https://i.ytimg.com/vi/EhNWzcUqGbI/hqdefault.jpg",
      "width": 480,
      "height": 360
     },
     "standard": {
      "url": "https://i.ytimg.com/vi/EhNWzcUqGbI/sddefault.jpg",
      "width": 640,
      "height": 480
     },
     "maxres": {
      "url": "https://i.ytimg.com/vi/EhNWzcUqGbI/maxresdefault.jpg",
      "width": 1280,
      "height": 720
     }
    },
    "channelTitle": "bradscottphotography",
    "categoryId": "28",
    "liveBroadcastContent": "none",
    "localized": {
     "title": "50 MPH 52v Electric Mountain Bike",
     "description": "http://voltbicycles.com This is our Alite 1000 Electric Mountain bike powered by a black lighting brushless rear hub electric motor with a 52v battery system. This electric bike will do around 50 MPH and will run 30+ miles on a single charge. \n\nGOING GREEN DOESN'T HAVE TO BE BORING"
    }
   }
  }
 ]
}



Как быть с текущей историей просмотров?


Текущая история просмотров хранится здесь:
www.youtube.com/feed/history
Нажимаете до победного конца на кнопку «Еще», пока не загрузится вся история, которая там хранится.
Далее сохраняем в html файл.
Я набросал небольшой парсер на perl, который выдергивает ID всех видео из сохраненного файла с историей.
use strict;
use warnings;
use utf8;
use Mojo::DOM;
use File::Slurp;
use feature 'say';

my $body = read_file( 'youtube_history.html', binmode => ':utf8' );
my $dom = Mojo::DOM->new($body);

for my $e ( $dom->find('div.yt-uix-tile')->each ) {
    say  $e->{'data-context-item-id'};

}


На выходе получаем список всех ID на ютюбе, которые были в youtube_history.html.
Можно загрузить его в нашу локальную базу и таким образом отметить видео, как просмотренное.

Немного о реализации на фреймворке flask


Ссылка на github:
github.com/Alexmod/memtube
На хабре была целая серия статей о flask, так что подробно не буду останавливаться.
Но если хотите запустить данный файл, то ставьте виртуальное окружение, устанавливайте все модули, которые нужны для старта,
и запускайте командой:
python main.py 

Если все ок, то увидете следующее:
 * Running on http://0.0.0.0:5000/
 * Restarting with reloader

Локальная версия youtube.com готова.
После первого запуска будет создан файл video.db в этой же директории, в котором и будет храниться информация о просмотрах.

P.S.


Чтобы смотреть видео на ютюбе с разных устройств и быть не привязанным к локальному компу, я выложил flask-сайт в онлайн:
http://memtube.com
И смотрю все оттуда.
У кого есть желание, пожалуйста, присоединяйтесь. На сайте в любой момент можно скачать Excel файл с историей просмотров:

Комментарии (11)


  1. Satellence
    21.04.2015 21:30
    +5

    image

    Я починил эту милоту…


    1. pcdesign Автор
      21.04.2015 21:32

      Спасибо. Заменил на ваш вариант.


  1. baka_cirno
    21.04.2015 21:33

    Я давно уже молча страдаю от этой проблемы. Особенно плохо, когда находишь интересный канал и хочешь просмотреть все, что там было отснято за последних 5 лет.
    Ваша идея интуитивно понятна, но я это себе представлял немного иначе. Это может быть связка веб-сервиса и расширения для браузера. Расширение автоматом следит за тем, что ты уже успел просмотреть и шлет эту информацию на сторонний сервер. А при отображении содержимого канала расширение берет эту информацию с сервера, маркируя соответствующее видео. Конечно, выглядит немного избыточно для такого пустяка, но это было бы реально удобно.


    1. pcdesign Автор
      21.04.2015 21:41

      Спасибо за коммент.
      Ага, тоже думал об этом. Но тут другие возникают вопросы.
      А как быть со всеми другими устройствами.
      Ну то есть можно смотреть и на телефоне, и на айпаде, и на компе, и на ноуте жены и т.д.
      И как потом это синхронизировать между устройствами.
      Поэтому и остановился на сайте, который всегда доступен с любого девайса.


    1. 007
      22.04.2015 22:02

      Я использую Feedly (rss-подписка) и youtube-dl (можно легко скачать канал или плейлист).


  1. dymonix
    21.04.2015 21:33

    Интересный вариант.
    На openshift возможно поднять?


    1. pcdesign Автор
      21.04.2015 21:42

      Да, можно :)
      Flask они официально поддерживают:
      developers.openshift.com/en/python-flask.html


  1. Raskaev
    21.04.2015 23:50

    Ошибку с 304 просмотрами исправили?


    1. pcdesign Автор
      22.04.2015 09:39

      А где у нас эта ошибка? Подскажите, плз.


      1. Raskaev
        22.04.2015 12:23

        Она не у вас, а у YouTube почему-то уже много лет :)


        1. pcdesign Автор
          22.04.2015 13:08

          Да, понял теперь этот прикол :)
          Знаменитая штука.
          Как-то я с утра не догнал.