суббота, января 29, 2011

Отмечание просмотренных серий на MyShows.ru

Оригинал с дополнениями, обсуждением и прочим здесь

Постановка задачи

Задача: автоматизировать рутинные действия по отмечанию просмотренных эпизодов на сайте myshows.ru. Поясню, после просмотра очередной серии Теории Большого Взрыва я открываю свой профиль, нахожу сериал, нахожу просмотренный эпизод и отмечаю его как «просмотренный».

После обнаружения api.myshows.ru сразу зародилась идея серьезно упростить этот процесс. Хотелось бы, чтобы это выглядело так: вызываем контекстное меню файла с только что просмотренной серией и выбираем «Отметить на myshows.ru».

В основе будет Ruby скрипт, который будет принимать имена файлов в качестве аргументов, определять имя сериала, номер сезона и эпизода и затем отмечающий серию в вашем профиле через API сайта.

API

Сначала было решено сделать обертку поверх их API на Ruby. Получилась ничем не примечательная библиотека myshows, использующая httparty для общения с сайтом. В силу общей занятости меня, в библиотеке реализован не весь функционал сайта, а только поиск сериалов/эпизодов и их отмечание, так как именно это необходимо для решения поставленной задачи. Вот пример использования:


Стоит заметить, что метод Profile#show, который ищет сериал по имени среди ваших сериалов, оптимизирован для поиска именно имен сериалов. Он может находить сериалы по аббревиатуре названия, по части названия, по названию без пробелов и так далее. Это сделано в связи с тем, что названия сериалов в имени файлов зачастую сильно коверкаются: lietome.s03e01.webdl.rus.novafilm.tv.avi вместо lie.to.me.s03e01.webdl.rus.novafilm.tv.avi, House.M.D.s07e01.rus.LostFilm.TV.avi вместо House.s07e01.rus.LostFilm.TV.avi и так далее.

Парсинг имени файла

Скрипт должен уметь, получив имя файла с серией, распознать в нем имя сериала, номер сезона и эпизода. Everybody stand back. I know regular expressions. Поискав по локальной сети форматы записи этой информации в имени файла, выделил два основных и написал соответствующие регулярные выражения:
  • title.s01e01.blah.blah.avi;
  • Title - 1x01 - Episode Title.avi.
Существуют так же вариации с другими разделителями или без них, это не сильно усложняет регулярные выражения. Они получается совсем нехитрые, Вы можете найти их в конечном коде скрипта в функции parse_filename.

Скрипт

Объединив парсинг имени файла и использование библиотеки myshows получается простой скрипт, который получив в качестве аргументов имена файлов, пытается отметить их в Вашем профиле и сообщает в stdout об успехе этого действия:


Имя пользователя и md5 пароля скрипт пытается вытащить из файла ~/.myshows, лучшего способа я не придумал.

Интеграция в файловый менеджер

Конечно этот скрипт можно использовать из других скриптов и из командной строки, но я все-таки смотрю сериалы открывая их двойным кликом в файловом менеджере.

Тут необходимо сказать, что я являюсь пользователем Mac OS X, и поэтому дальнейшие слова будут именно об интеграции ранее написанного скрипта с этой ОС. Если Вам это не интересно, можете перейти сразу к заключению.

Будем использовать Automator. Необходимо создать новую Службу, которая будет получать «выбранные файлы фильмов» в «любой программе».

Добавляем действие «Запустить shell-скрипт», выбираем в качестве языка «/usr/bin/ruby» с передачей ввода «как аргументов». Затем вставляем ранее написанный скрипт в поле для ввода скрипта, заменив то, что там было (для красоты можно удалить первую строку "#!/...").

Добавляем действие «Запустить AppleScript». Необходимо в каком-либо виде вывести информационные сообщения, которые печатал скрипт. Было решено воспользоваться функцией display dialog, получается примерно такой AppleScript:


Должно было получиться что-то похожее на это:


Служба готова к использованию, остается только сохранить и придумать имя. Теперь в Finder можно ее вызвать:


Заключение

Оно работает, это радует.

Измерения показали что среднее время работы скрипта 2-5 секунд на отмечание серий одного сериала, то есть отметить один эпизод сериала и десять займет примерно одинаковое время, а вот отметить пилотные серии десяти разных сериалов займет 20-50 секунд, что, в принципе, никому не нужно. Самое узкое место всей системы — это запросы к сайту и выкачивание больших списков эпизодов. Служба созданная Automator'ом работает по-дольше, есть постоянная добавка.

А теперь у меня есть обращение к тем, кого заинтересовала эта идея. Наверняка есть люди, которые отмечают сериалы на myshows.ru и пользуются Windows, KDE, Gnome, …. Сам Ruby-скрипт является кросс-платформенным, но вот интеграция с конкретным файловым менеджером — нет. В связи с этим ищутся люди, которые смогли бы рассказать, как интегрировать подобный Ruby-скрипт в их любимый файловый менеджер.

вторник, декабря 14, 2010

Google?

Этим летом меня удивило письмо с темой «Hello from Google Zurich», оказывается меня через GitHub нашел гугл, точнее один из сотрудников по поиску кадров. Был небольшой телефонный разговор, сошлись на том, что до конца 4-го курса я точно учусь и никуда не поеду, а потом со мной может когда-нибудь и свяжутся (я так до конца и не понял, но возможно по окончании 4-го курса), чтобы позвать на стажировку.
И вот несколько недель назад мне пришло «from Google Russia», в Московском и Питерском офисе открыты вакансии на инженеров-стажеров. Я опять сказал, что никуда пока не хочу, хочу учиться. Предложили прособеседоваться, так, на будущее.. Я был не против, и вот, на 13 декабря договорились провести со мной телефонное собеседование.
(история гораздо длиннее и интереснее, но я хочу рассказать именно о собеседовании)

Ровно в два часа дня, как и договаривались, позвонил Костя, программист из московского офиса. Собеседование состояло из трех частей: введение (по-русски, объяснили что щас будет происходить), собственно собеседование (по-английски, я должен был отвечать на вопросы) и свободный разговор (по-русски, я мог задавать вопросы). Предварительно для меня расшарили текстовичок в Google Docs, в котором происходил весь обмен письменной информацией, вполне удобно.

So let's start. Дан массив X[n] и число Y, найти такие i ≠ j, что X[i] + X[j] = Y. Гавно вопрос! За O(n²) полным перебором. Костя захотел чего-нибудь более.. Быстрого. Я решил, что O(n) все равно недостижимо (я был так наивен), и тогда не грех и отсортировать массив за O(n log(n)). Отсортированный массив это хорошо, напрашиваются два индекса, идущие с разных сторон, пусть i слева, j справа. Тут я немного затупил, но Костя попросил медленно вслух повторить мысль и затуп разрешился. Смотрим текущую сумму X[i] + X[j], если она равна Y, то разговор окончен, если она меньше Y, то двигаем i вправо, ибо j двигать влево бесполезно, если она больше Y, то двигаем j влево. Повторяем сие действо, пока i < j. Иначе решения нет. Костя согласился с алгоритмом, попросил определить скорость — O(n), попросил доказать — доказал. (Уже после собеседования я смог строго доказать корректность алгоритма, Костя не прикапывался). Получаем в итоге O(n log(n)), я решил что неплохо, но меня так между делом спросили: "А за O(n) слабо?!" Задумался минут на 5... Предложили подсказку: какие контейнеры в Java я знаю. List, vector, hash map, .. Меня остановили, спросили, что я знаю про hash map. Я начал лечить что у него время доступа линейное, точнее почти линейное.. Понял что несу чушь, поправился, время доступа константное. "So could you use hash map here?" YES — крикнул я, не скрывая ощущения полного офигевания от простоты алгоритма, который уже понял. Идем по массиву, и добавляем каждый элемент X[i] в хэш таблицу следующим образом {ключ: x[i], значение: i}, и также проверяем в таблице наличие элемента с ключом (Y-X[i]), если он есть, то берем соответствующее ему значение j и пара i,j является искомой. Линейное время, память конечно покушается в некотором количестве, но как я понял тут было важно время.
So another task. Есть функция int foo(int x) { return x*100; }, реализовать эквивалентную ей, не используя операцию умножения. Гавно вопрос! x << 6 + x << 5 + x << 2. Костя согласился и предложил обобщить: написать алгоритм, которой для произвольного N будет генерировать выражение равное x*N. Написал алгоритм нахождения максимальной степени двойки, непревосходящей N (двигаем вправо, пока число положительно; считаем сдвиги). Дальше повторяя этот алгоритм получаем конечное разложение N на сумму степеней двойки: x << k₀ + x << k₁ + ... . Костя хитрым голосом предложил продемонстрировать работу алгоритма при N = 15. Вышло стремно: 8 + 4 + 2 + 1, можно ли как-нибудь по-лучше? Да, (x << 4) - x. Написал алгоритм для нахождения и этой степени, в итоге вышло  x << k₀ - x << k₁ + x << k₂ - x << k₃ + ... . Этот алгоритм вроде не является лучше, ибо очень много зависит от начального числа, но Костя сказал ОК и сообщил, что 40 минут отведенные на собеседование кончились.

Фуух, я очень волновался, и эти 40 минут пролетели нереально быстро. Костя оказался выпускником МехМата МГУ, уже более трех лет работает в гугл, как я понял ему очень нравится. Оказалось, что они не gmail на русский переводят, а деляет вполне секретные и интересные проекты вместе с зарубежными коллегами. Поинтересовался, действительно ли их офисы такие клевые.. Да, клевые, но вот он уже привык и гораздо больше акцентировал внимание на том, что работа интересная. Пожелали друг другу удачи и все.

Никаких результатов, как я понимаю, не узнать, ну что ж, будем ждать писем ближе к лету. Работать в гугл не уверен, что хочу, но от стажировки точно не откажусь.

p.s. К собеседованию никак не готовился, проходил по большей части для себя.

суббота, августа 21, 2010

Контрольная по математике в ЛШ-2010

У меня окончилась работа в Летней Школе. В этот раз у меня было много нового, меня приглашали проверять олимпиаду вступительную и принимать собеседования, но сейчас о другом.

Вел математику опять у класса 9-4, 29 человек в двух группах. Были умные, были неочень :)

Теперь конкретно по контрольной: пять задач (метод мат.индукции, делимость, планиметрия, комбинаторика, построения циркулем и линейкой), на все 4 часа. Мне потребовалась 21 минута, чтобы решить оба варианта, так что воздержусь от субъективной оценки уровня задача, но судя по общим результатам контрольная сложная.

Средний бал по классу 9.8, что соответстует двум задачам при оценке из пяти баллов. За такой результат ставили три. Разбаловка вообще простая: больше одной задачи — три, больше двух — четыре, больше трех — пять. В классе же 4 пятерки, 7 четверок, 10 троек, 8 двоек.

А теперь интересная статистика..
  • задачку на делимость решали 27 человек, причем 19 решили верно! Это говорит о том, что все-таки толк от меня есть, и работе с остатками я их научил
  • задачку на мат.индукции решали 24 человека, а решили опять же 19. Это опять говорит о том, что я молодец, но все-таки боязнь перед "страшной индукцией" присутвует, и далеко не все понимают теор.основу мат.индукции
  • задача на комбинаторику была жесткая, пытались решать и решили ее только 2 человека. В задаче нужно было использовать прием, который я на семинарах не давал, бывает
  • планиметрию решали 9 человек, решили 2. Она даже не была сложной. Просто почему-то второй год подряд ЛШата вообще не шарят в планиметрии (или это традиция такая?)
  • задачу на построения решали 14 человек, решили 6. А вот это я объяснить не могу, на семинарах основы разбирали, вроде все было понятно, единственное при проверке очень прикапывались к оформлению, может в этом дело
Теперь о рекомендациях. В ЛШ преподаватели должны по результатам семинаров выставить каждому ученику рекомендацию по шкале от "настоятельно не рекомендую" до "настоятельно рекомендую". В этом году все дети были вроде адекватные, поэтому "не рекомендую" я не ставил.
Можно попробовать выявить закономерность между рекомендацией (зеленые линии на графике) и оценкой за контрольную (синяя) — я не смог. Это отчасти связано с тем, что многие дети не хотят поступать и сливают контрольную не особо стараясь, а всякие упрямые и целеустремленные девочки делают все, чтобы написать хорошо.

В общем я доволен, на следующий год обязательно пойду преподом и опять буду думать о должности воспета.

четверг, июля 29, 2010

Стиль "прямоугольник"

Нашел в одном style-guid'е, очень красивый пример:

Форматирование исходного текста в стиле "прямоугольник", например
crlf    = (String) java.security.AccessController 
          .doPrivileged(new sun.security.action   
          .GetPropertyAction("line.separator"));  
есть неуважение к людям, которые вынуждены будут этот текст читать.