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

Собственно сразу результат: Ссылка на сервис

Дальше больше :)


Инструкция

Все работает довольно просто. Авторизуете приложение, даете ему доступ к друзьям. Сервис абсолютно безопасен, все исходные коды открыты, да и сам API не позволит сделать что-то плохое.

После выгрузки, полученный ics файл (это формат iCalendar) можно загрузить в любой календарь. P.S. Проверял пока только с Гугл календарем, но должно заработать везде.

Справка по импорту в google calendar: ссылка

Важно! Импортируйте в новый календарь, иначе, если что не так, придется потратить немало времени на чистку )


Техническая часть

Задача: Сделать так, что бы в календаре (например, google)  можно было быстро добавить дни рождения друзей из vk. Было бы круто, увидеть список и выбрать записи для выгрузки.

Мысли: Логично, что сервис должен получиться легким, доступным всем, без установки, так же будет круто, если не потребуется ничего, кроме стандартного хостинга. Хм… JavaScript! У VK есть отличный SDK

Реализация: Круто, API есть, нужно подобрать модули, которые облегчат разработку. Гугл, StackOwerflow и GitHub мне в помощь. Вот что я нашел:

Для приличного внешнего вида подключаю Bootstrap, так же без него не заработает плагин для работы с таблицей.

Для начала:

  1. Создаем приложение тут
    1. Тип выбираем веб-приложение.
    2. Для удобной локальной отладки в базовый домен добавляем localhost
    3. Запоминаем ID приложения
  2. Подключаем js API. Вот тут описано как
  3. Реализуем задуманный функционал

Логика работы и код:

  1. При загрузке проверяем, не авторизованы, ли мы уже
    $(document).ready(function () {
        VK.Auth.getLoginStatus(function (r) {
            if (r.session) {
                console.log("Already auth");
                uiLogin();
            }
            else {
                console.log("Not auth");
            }
        });
    });
  2. Для авторизации вызываем соответствующий метод
    VK.Auth.login(
    	function (r) {
    		if (r.session) {
    			uiLogin();
    		}
    	},
    	VK.access.FRIENDS
    );
  3. Получить информацию о пользователе
    VK.Api.call(
            "users.get",
            {fields : "first_name,second_name"},
            function (r) {
                if (r.response) {
                    $("#userInfo").text("  Пользователь: " + r.response[0].first_name + " " + r.response[0].last_name);
                }
            }
    );
  4. Обращаемся к API вк, для получения списка друзей (метод «friends.get«). Запросим нужные нам поля
    VK.Api.call(
    	"friends.get",
    	{
    		order: "name",
    		fields: "bdate,nickname,city,domain"
    
    	},
    	function (r) {
    		...
    	}
    );

    Тут есть один момент. Города возвращаются как id, а не названия. Не порядок. В вк есть вспомогательный метод, для получения данных о городе по id («database.getCitiesById«), он отлично нам подходит, на вход нужно передать список id. Тянуть все города для страны — не корректно.

    // Эта функция поможет вывести массив, только с существующими значениями
    // По сути так я добился от массива поведения похожего на java Set
    function fToStr() {
        var str = "";
        for (i = 0; i < this.length; i++) {
            if (this[i] === undefined) continue;
            str += this[i];
            if (i + 1 < this.length) str += ",";
        }
        return str;
    }
    Array.prototype.toStr = fToStr;
    
    // После получения ответа от вк, пробежимся по него и соберем все города
    var cityIds = [];
    filterResp.forEach(function (e) {
    	cityIds[e.city] = e.city;
    });
    
    // Для получения строчки 1,5,9 воспользуемся нашей функцией
    cityIds.toStr();
  5. Дальше подготовим данные для вывода таблицы. Здесь интерес представляет формат даты, приходящий от вк. Я написал такой код. Для людей, скрывших свой год, будем ставить 1900
    // now Date from vk response
    var dt = e.bdate.split(".");
    var date;
    if (dt.length == 2) {
    	// DD.MM
    	date = new Date("1900", dt[1] - 1, dt[0]);
    } else {
    	// DD.MM.YYYY
    	date = new Date(dt[2], dt[1] - 1, dt[0]);
    }
  6. Инициализируем таблицу. Здесь все по документации плагина bootstrap-table.
  7. Таблица отрисована. Теперь ждем от пользователя, пока он выберет все нужные строки для экспорта.
  8. По нажатию кнопки экспорт, собираем все отмеченные строчки, создаем ивенты для календаря и экспортируем
    var cal = ics("ru-RU");
        c = 0;
        birtdayList.forEach(function (e) {
            if ($("input#"+e.uid).prop("checked")) {
                cal.addEvent(
                    "ДР " + e.first_name + " " + e.last_name,
                    e.link,
                    e.city,
                    e.birthday, e.birthday);
                c++;
            }
        });
        alert("Будет выгруженно " + c + " дней рождений");
    cal.download("vk-birtdays");
  9. Что бы создать ежегодно повторяющиеся мероприятия, я внес изменения в библиотеку. Измененная мной версия тут. Так же пригодилась спецификация формата iCalendar (ics)

Ссылка на проект в GitHub: sboychenko/vk-birthday-exporter