Как стать автором
Обновить

Создание YouTube-плеера для Nokia N9 на QML

Время на прочтение14 мин
Количество просмотров2K
В процессе изучения YouTube API возникла идея написать YouTube плеер для Nokia N9. При выборе средства реализации выбор пал на набирающий обороты QML. Т.к. QML очень легко интегрируется с JavaScript, то получать фиды YouTube было решено именно в JSON (JavaScript Object Notation) формате. При создании пользовательского интерфейса на QML за основу был взят пример Flickr Mobile из QtSDK. Загруженный из фида список предоставляется пользователю в виде ListView или GridView и при щелке пользователя на выбранном видео оно открывается в установленном по умолчанию видео-плеере.

Далее в статье будет более подробно показано, как это все выглядит и как реализуется.

Выглядит это все примерно так:
image
image
image

Итак, для начала создадим функцию loadYouTube() на JavaScript, которая будет загружать JSON-объект с YouTube посредством HTTP запроса и парсить его. По умолчанию тег для поиска видео rssModel.tags выставим в Nokia N9 и количество отображаемого контента в 32. Далее — код этой функции:
  1. function loadYouTube(){
  2.     var doc = new XMLHttpRequest();
  3.     doc.onreadystatechange = function() {
  4.         if (doc.readyState == XMLHttpRequest.DONE) {
  5.             var jsresp = JSON.parse(doc.responseText);
  6.             var entries = jsresp.feed.entry;
  7.             var len = entries.length
  8.             rssModel.clear();
  9.             var vi=1;
  10.             for (var i = 0; i < len; i++) {
  11.                 var obj = entries[i];
  12.                 rssModel.append( {
  13.                                 number:
  14.                                 i + 1,
  15.                                 url:
  16.                                 (function() {
  17.                                      try {return(obj.id.$t.replace("http://gdata.youtube.com/feeds/api/videos/", ""));}
  18.                                      catch(e) { return("(no title)"); }
  19.                                  }    )(),
  20.                                 videoRTSP:
  21.                                 (function() {
  22.                                      try {
  23.                                          return(obj.media$group.media$content[1].url);
  24.                                      }
  25.                                      catch(e) { return("(no title)"); }})(),
  26.                                 videoHTTP:
  27.                                 (function() {
  28.                                      try {
  29.                                          return(obj.media$group.media$content[0].url);
  30.                                      }
  31.                                      catch(e) { return("(no title)"); }})(),
  32.                                 tags:
  33.                                 (function() {
  34.                                      try {
  35.                                          return(obj.yt$statistics.viewCount);
  36.                                      }
  37.                                      catch(e) { return("(no title)"); }})(),
  38.                                 photoType:
  39.                                 (function() {
  40.                                      try {
  41.                                          return(obj.category[0].term);
  42.                                      }
  43.                                      catch(e) { return("(no title)"); }})(),
  44.                                 description:
  45.                                 (function() {
  46.                                      try {
  47.                                          return(obj.content.$t);
  48.                                      }
  49.                                      catch(e) { return("(no title)"); }})(),
  50.                                 photoAuthor:
  51.                                 (function() {
  52.                                      try {
  53.                                          return(trimString(obj.author[0].name.$t,35));
  54.                                      }
  55.                                      catch(e) { return("(no title)"); }})(),
  56.                                 photoHeight:
  57.                                 (function() {
  58.                                      try {
  59.                                          return(obj.media$group.media$thumbnail[0].height);
  60.                                      }
  61.                                      catch(e) { return("(no title)"); }})(),
  62.                                 photoWidth:
  63.                                 (function() {
  64.                                      try {
  65.                                          return(obj.media$group.media$thumbnail[0].width);
  66.                                      }
  67.                                      catch(e) { return("(no title)"); }})(),
  68.                                 photoDate:
  69.                                 (function() {
  70.                                      try {
  71.                                          return(obj.published.$t);
  72.                                      }
  73.                                      catch(e) { return("(no title)"); }})(),
  74.                                 imagePath:
  75.                                 (function() {
  76.                                      try {
  77.                                          return(obj.media$group.media$thumbnail[0].url);
  78.                                      }
  79.                                      catch(e) { return("(no title)"); }})(),
  80.                                 title:
  81.                                 (function() {
  82.                                      try {
  83.                                          return(trimString(obj.title.$t,35));
  84.                                      }
  85.                                      catch(e) { return("(no title)"); }})()
  86.             });
  87.             }
  88.             console.log("Successfully")
  89.         }
  90.     }
  91.     doc.open("GET", "http://gdata.youtube.com/feeds/api/videos?q="+rssModel.tags+"&orderby=viewCount&alt=json&max-results=32");
  92.     doc.send();
  93. }


Все загруженные и распарсенные данные с YouTube добавляем в QML ListModel:
  1. ListModel{id:rssModel; property string tags :"Nokia N9";}


Для отображения данных в том виде, в каком показано выше на скриншотах, мы добавляем созданную модель в model property для элементов Grid View и List View:
  1. Mobile.GridDelegate { id: gridDelegate }
  2. GridView {    
  3.     id: photoGridView; model: rssModel; delegate: gridDelegate; cacheBuffer: 100    
  4.     cellWidth: (parent.width-2)/4; cellHeight: cellWidth; width: parent.width; height: parent.height - 1;    
  5. }
  6.  
  7. Mobile.ListDelegate { id: listDelegate }
  8. ListView {    
  9.     id: photoListView; model: rssModel; delegate: listDelegate;    
  10.     width: parent.width; height: parent.height; x: -(parent.width * 1.5); cacheBuffer: 100;    
  11. }


Когда пользователь щелкнет на выбранном элементе, мы вызываем метод Qt.openUrlExternally(), который откроет потоковое видео в дефолтном плеере:
  1. MouseArea{
  2.             id:listMouseArea
  3.             anchors.fill: parent
  4.             onClicked: Qt.openUrlExternally(videoRTSP);
  5. }


Добавляем в приложение меню для выбора тэга и количества отображаемых элементов, кнопки для обновления контента и смены способа отображения результатов поиска и всё — плеер готов.
Теги:
Хабы:
Всего голосов 17: ↑16 и ↓1+15
Комментарии9

Публикации