diff --git a/Firefox/data/js/popup.js b/Firefox/data/js/popup.js index 496b3c3..0eba35e 100644 --- a/Firefox/data/js/popup.js +++ b/Firefox/data/js/popup.js @@ -73,8 +73,8 @@ function main(data, translation) { //@param i integer the account index function loadNewVideos(i) { updateMsg.eq(1).text(data.channels[i].name); - loadVideos(data.channels[i].id).done(function(response) { - var videos = proccessYoutubeFeed(response.feed); + loadVideos(data.channels[i].uploadsPlayListId).done(function(response) { + var videos = proccessYoutubeFeed(response.items); var save = false; if (videos) { var account = { @@ -135,7 +135,7 @@ function main(data, translation) { for (var i = 0; i < data.channels.length; i++) { var account = data.channels[i]; //populate html - sidebarHTML += '
' + + sidebarHTML += '
' + '
'; @@ -148,22 +148,17 @@ function main(data, translation) { var self = $(this); //the account name, ej: "PMVTutoriales" var accountName = self.find('img:first').attr('title'); - //the Youtube account ID which is some long string - var accountYoutubeID = self.attr('id'); + //the Youtube account PLAYLIST ID which is some long string + var accountPlayListId = self.attr('id'); //the account number (integer), ej: 7 var accountID = self.parent().data('id'); - /* - Sometimes account names have spaces, in which case we can't load its videos - so we use the youtube id which is secure - */ - var account = accountYoutubeID; //click listener self.off("click").click(function(event) { selectedAccount = accountID; $('.selected:first').removeClass('selected'); self.parent().addClass('selected'); - loadVideos(account).done(function(response) { - var videos = proccessYoutubeFeed(response.feed); + loadVideos(accountPlayListId).done(function(response) { + var videos = proccessYoutubeFeed(response.items); if (videos) { var html = generateSideBarVideosHTML(videos); //display account name @@ -180,18 +175,19 @@ function main(data, translation) { /** * Loads most recent Youtube videos from selected account - * @param {String} accountName the account name or ID + * @param {String} playListId the id of the uploads play list */ - function loadVideos(accountName) { + function loadVideos(uploadsPlayListId) { return $.ajax({ - url: 'https://gdata.youtube.com/feeds/api/users/' + accountName + '/uploads', + url: 'https://www.googleapis.com/youtube/v3/playlistItems', dataType: 'json', cache: false, data: { - v: 2, - alt: 'json', - "start-index": 1, - "max-results": 4 + 'part': 'snippet', + 'key': 'AIzaSyBbTkdQ5Pl_tszqJqdafAqF0mVWWngv9HU', + 'maxResults': 4, + 'playlistId': uploadsPlayListId, + 'fields': 'items(snippet,status)' } }); } @@ -202,31 +198,36 @@ function main(data, translation) { * @return {Array} videos an array containing objects with each videos' meta-data */ function proccessYoutubeFeed(data) { - var feed = data.entry; - var videos = []; - if (feed === undefined) { - //error this account has no videos - return false; - } - for (var i = 0; i < feed.length; i++) { - var entry = feed[i]; - var title = entry.title.$t; //Video title - var link = entry.link[0].href; //Video link - var img = entry.media$group.media$thumbnail[1].url; //video thumbnail - var description = entry.media$group.media$description.$t; //video description - var author = entry.author[0].name.$t; //creato's Youtube name - - videos.push({ - "id": i, //the video number (0 -> 3) - "title": title, - "url": link, - "thumbnail": img, - "description": description, - "author": author - }); - } - return videos; - } + var videos = []; + if (data === undefined) { + //error this account has no videos + return false; + } + + var snippets; + var youtubeVideoUrl = 'https://www.youtube.com/watch?v='; + + for (var i = 0; i < data.length; i++) { + + snippets = data[i]; + for (var key in snippets) { + if (snippets.hasOwnProperty(key)) { + var snippet = snippets[key]; + + videos.push({ + "id": i, //the video number (0 -> 3) + "title": snippet.title, + "url": youtubeVideoUrl + snippet.resourceId.videoId, + "thumbnail": snippet.thumbnails.medium.url, + "description": snippet.description, + "author": snippet.channelTitle + }); + } + } + + } + return videos; + } /** * Display's the account's videos on the popup diff --git a/Firefox/data/js/upgrade.js b/Firefox/data/js/upgrade.js new file mode 100644 index 0000000..0a68838 --- /dev/null +++ b/Firefox/data/js/upgrade.js @@ -0,0 +1,20 @@ +//Firefox - upgrade.js + +//get all strings to translate +var strings = []; +for (var i = 1; i <= 9; i++) + strings.push("errMsg" + i); + +strings.push("lang"); +//translate +self.port.emit("translation", strings); +self.port.once("translation", function(response) { + var translation = response.translation; + //../locales/es/logo.png + $("#logo").css("background-image", "url('./locales/" + translation.lang + "/logo.png')"); + main(response.data, translation, response.addonVersion); +}); + +function main(ExtensionData, translation, addonVersion) { + window.alert('helo'); +} \ No newline at end of file diff --git a/Firefox/data/js/youtubeMod.js b/Firefox/data/js/youtubeMod.js index 7734fb7..cf2ab91 100644 --- a/Firefox/data/js/youtubeMod.js +++ b/Firefox/data/js/youtubeMod.js @@ -13,12 +13,12 @@ self.port.once("channels", function(channels) { userName = document.getElementsByClassName('yt-user-info')[0]; userName = userName.getElementsByTagName('a')[0]; userName = userName.getAttribute('data-ytid'); - userName = userName.substring(2).trim(); + userName = userName.trim(); } else { onWatchPage = false; userName = document.getElementsByClassName('yt-uix-subscription-button')[0]; userName = userName.getAttribute('data-channel-external-id'); - userName = userName.substring(2).trim(); + userName = userName.trim(); } for (var i = channels.length - 1; i >= 0; i--) { if (userName === channels[i].id) { diff --git a/Firefox/data/options.html b/Firefox/data/options.html index 041dac4..1ea5087 100644 --- a/Firefox/data/options.html +++ b/Firefox/data/options.html @@ -26,9 +26,9 @@
- +
diff --git a/Firefox/data/upgrade.html b/Firefox/data/upgrade.html new file mode 100644 index 0000000..59dc3c7 --- /dev/null +++ b/Firefox/data/upgrade.html @@ -0,0 +1,33 @@ + + + + + + + + + + +
+ +
+ + +

Please Wait while we upgrade My Youtube....

+ +
+ +
+ + + \ No newline at end of file diff --git a/Firefox/lib/Mi_Youtube_Data_2.js b/Firefox/lib/Mi_Youtube_Data_2.js index 2531d02..0e4201e 100644 --- a/Firefox/lib/Mi_Youtube_Data_2.js +++ b/Firefox/lib/Mi_Youtube_Data_2.js @@ -2,24 +2,21 @@ My Youtube Data This file contains a "class" to save the extensions data */ - -function MY_YOUTUBE_DATA(location) -{ +function MY_YOUTUBE_DATA(location) { this.storage = location; this.data = { name: "MyYoutubeData", - version: 3, - channels: [ - { - //default PMVTutoriales channel - id: "ZgwLCu6tSLEUJ30METhJHg", - name: "PMVTutoriales", - thumbnail: "https://i3.ytimg.com/i/ZgwLCu6tSLEUJ30METhJHg/1.jpg?v=516a0349", - videoTitles: [], - newVideos: false, - url: "https://www.youtube.com/user/PMVTutoriales" - } - ], + version: 3.1, + channels: [{ + //default PMVTutoriales channel + id: "UCZgwLCu6tSLEUJ30METhJHg", + name: "PMVTutoriales", + thumbnail: "https://yt3.ggpht.com/-mrEkpcfUuX4/AAAAAAAAAAI/AAAAAAAAAAA/cWFyINwhD9s/s88-c-k-no/photo.jpg", + videoTitles: [], + newVideos: false, + url: "https://www.youtube.com/channel/UCZgwLCu6tSLEUJ30METhJHg", + uploadsPlayListId: "UUZgwLCu6tSLEUJ30METhJHg" //needed for Youtube API V3 + }], prefs: { "show_popup": true, "play_popup_sound": true, @@ -35,16 +32,20 @@ function MY_YOUTUBE_DATA(location) } MY_YOUTUBE_DATA.prototype.load = function(callback) { - if (!this.storage[this.name]) + var upgrade = false; + if (!this.storage[this.name]) { + //firt install, save data this.setValue(this.name, this.data); - else if (this.storage[this.name].version != this.version) { - //update defaults values without losing already existing values - //currently not needed - } - else { + } else if (this.storage[this.name].version != this.version) { + upgrade = true; + this.data.isNewInstall = false; + this.storage[this.name].channels[0] = this.data.channels[0]; + this.data.channels = this.storage[this.name].channels; + } else { this.data = this.storage[this.name]; } - callback(this.data); + + callback(this.data, upgrade); }; MY_YOUTUBE_DATA.prototype.setValue = function(name, value) { @@ -68,4 +69,12 @@ MY_YOUTUBE_DATA.prototype.delete = function() { delete this.storage[this.name]; }; +function update(target, source) { + var a = Object.create(target); + Object.keys(source).map(function(prop) { + prop in a && (a[prop] = source[prop]); + }); + return a; +} + exports.MY_YOUTUBE_DATA = MY_YOUTUBE_DATA; \ No newline at end of file diff --git a/Firefox/lib/main.js b/Firefox/lib/main.js index ec97299..3f5120f 100644 --- a/Firefox/lib/main.js +++ b/Firefox/lib/main.js @@ -13,34 +13,40 @@ tmr.setTimeout(function() { var DATA = new DATABASE.MY_YOUTUBE_DATA(SS.storage); //we want the user's FF version for version-dependent features var FF_VERSION = parseInt(require("sdk/system").version); + //todo - inform user he's using too much info //SS.on("OverQuota", function() { //window.alert('Storage limit exceeded'); //}); - DATA.load(function(ExtensionData) { - //---------required modules & setup ------------------------------- - //var {ActionButton} = require("sdk/ui/button/action"); //button ui - var { - ToggleButton - } = require('sdk/ui/button/toggle'); - var { - Panel - } = require("sdk/panel"); //panel (for main popup) +//---------required modules & setup ------------------------------- + var {ToggleButton} = require('sdk/ui/button/toggle'); + var {Panel} = require("sdk/panel"); //panel (for main popup) var Request = require("sdk/request").Request; //network requests var tabs = require("sdk/tabs"); var translate = require("sdk/l10n").get; var notifications = require("sdk/notifications"); var pageMod = require("sdk/page-mod"); //needed to add contentscripts var self = require("sdk/self"); - var optionsURL = "options.html"; + var upgradeURL = "upgrade.html"; + + DATA.load( function(ExtensionData, upgrade) { + if (upgrade) { + upgradeInit(ExtensionData); + } + else { + init(ExtensionData); + } + + + function init(ExtensionData) { //first install if (ExtensionData.isNewInstall) { - getYoutuber("ZgwLCu6tSLEUJ30METhJHg", function(response) { - response = response.json; - ExtensionData.channels[0].videoTitles = getVideoTitles(response.feed); + getYoutuber("UUZgwLCu6tSLEUJ30METhJHg", function(response) { + response = response.json.items; + ExtensionData.channels[0].videoTitles = getVideoTitles(response); ExtensionData.isNewInstall = false; DATA.save(ExtensionData); openOptions(); @@ -116,23 +122,23 @@ tmr.setTimeout(function() { worker.port.emit("channels", ExtensionData.channels); }); worker.port.on("addYoutuber", function(userName) { - /*sadly, we have to make 2 network requests + /*sadly, we have to make 2 network requests one to get the channel thumbnail and the second one to get the videos because youtube*/ getYoutuber(userName, function(res) { if (res.statusText === "OK") { - res = res.json; - getYoutuber(userName, function(response) { + channel = res.json.items[0]; + var uploadsPlayListId = channel.contentDetails.relatedPlaylists.uploads; + getYoutuber(uploadsPlayListId, function(response) { if (response.statusText === "OK") { - response = response.json; - var youtuber = response.feed; ExtensionData.channels.push({ - 'id': res.entry.author[0].yt$userId.$t, - 'name': youtuber.author[0].name.$t, - 'thumbnail': res.entry.media$thumbnail.url, - 'videoTitles': getVideoTitles(youtuber), + 'id': channel.id, + 'name': channel.snippet.title, + 'thumbnail': channel.snippet.thumbnails.default.url, + 'videoTitles': getVideoTitles(response.json.items), 'newVideos': false, - 'url': res.entry.link[0].href + 'url': 'https://www.youtube.com/channel/' + channel.id, + 'uploadsPlayListId': uploadsPlayListId }); DATA.save(ExtensionData); worker.port.emit("done", { @@ -208,7 +214,6 @@ tmr.setTimeout(function() { } //-------------check videos----------------------------------- - var totalNewVideos = 0; var newVideosHash = ''; var oldVideosHash = ''; @@ -221,9 +226,9 @@ tmr.setTimeout(function() { function checkNewVideos(count) { //we need to get the lastest data var account = ExtensionData.channels[count]; - getYoutuber(account.id, function(response) { + getYoutuber(account.uploadsPlayListId, function(response) { response = response.json; - var newVideosCount = compareVideos(getVideoTitles(response.feed), account.videoTitles); + var newVideosCount = compareVideos(getVideoTitles(response.items), account.videoTitles); var save = false; //if newVideosCount > 0, add the number to the total newVideos number if (newVideosCount) { @@ -231,7 +236,7 @@ tmr.setTimeout(function() { totalNewVideos += newVideosCount; newVideosHash += account.name + totalNewVideos; - /* + /* this is probably quite messy basically, instead of just counting how many new videos we have we want to SAVE those new videos, that way, when the popup shows @@ -240,7 +245,7 @@ tmr.setTimeout(function() { this of course, needs to be re-factored since we are doing kind of the same thing in popup.js */ - var videos = proccessYoutubeFeed(response.feed); + var videos = proccessYoutubeFeed(response.items); var _account = { "accountName": ExtensionData.channels[count].name, "accountIndex": count, @@ -306,32 +311,59 @@ tmr.setTimeout(function() { }, true); } - function getYoutuber(account, callback, getVideos) { - var url = 'http://gdata.youtube.com/feeds/api/users/' + account; - var params = { - "v": 2, - "alt": 'json' - }; - //extra parameters needed to get account videos - if (getVideos) { - url += '/uploads'; - params['start-index'] = 1; - params['max-results'] = 4; + //@param Array data + function getVideoTitles(data) { + var result = []; + var snippets; + + for (var i = 0; i < data.length; i++) { + snippets = data[i]; + for (var key in snippets) { + if (snippets.hasOwnProperty(key)) { + var snippet = snippets[key]; + if (snippet.title !== undefined) { + result.push(snippet.title); + } + } + } + } + return result; + } - Request({ - url: url, - headers: { - 'Cache-control': 'no-cache' - }, - content: params, - onComplete: function(response) { - callback(response); - }, - }).get(); + function proccessYoutubeFeed(data) { + var videos = []; + if (data === undefined) { + //error this account has no videos + return false; + } + + var snippets; + var youtubeVideoUrl = 'https://www.youtube.com/watch?v='; + + for (var i = 0; i < data.length; i++) { + + snippets = data[i]; + for (var key in snippets) { + if (snippets.hasOwnProperty(key)) { + var snippet = snippets[key]; + + videos.push({ + "id": i, //the video number (0 -> 3) + "title": snippet.title, + "url": youtubeVideoUrl + snippet.resourceId.videoId, + "thumbnail": snippet.thumbnails.medium.url, + "description": snippet.description, + "author": snippet.channelTitle + }); + } + } + + } + return videos; } - function getVideoTitles(data) { + /*function getVideoTitles(data) { var entries = data.entry, result = []; if (entries === undefined) { @@ -345,6 +377,7 @@ tmr.setTimeout(function() { } function proccessYoutubeFeed(data) { + var feed = data.entry; var videos = []; if (feed === undefined) { @@ -369,11 +402,11 @@ tmr.setTimeout(function() { }); } return videos; - } + }*/ function compareVideos(a, b) { - var length = a.length, - diff = 0; + var length = a.length; + var diff = 0; for (var i = 0; i < length; i++) { var add = 1; for (var j = 0; j < length; j++) { @@ -509,6 +542,111 @@ tmr.setTimeout(function() { return true; } - }); + } + + function upgradeInit(ExtensionData) { + //tabs.open(self.data.url(upgradeURL)); + + /*pageMod.PageMod({ + include: self.data.url(upgradeURL), + contentScriptFile: [ + self.data.url("js/jquery2.js"), + self.data.url("js/upgrade.js") + ], + //port event listeners + onAttach: function(worker) { + var translation = {}; + //listen for translation request + worker.port.once("translation", function(strings) { + for (var i = 0; i < strings.length; i++) { + //translate + translation[strings[i]] = translate(strings[i]); + } + //send translation + worker.port.emit("translation", { + data: ExtensionData, + translation: translation, + addonVersion: self.version + }); + }); + } + });*/ + + var channel; + var name; + var id; + /* + Due to the changes in Youtube's API V3, we need to update our channels array and objects + to include a new property "uploadsPlayListId" because we need that ID to retreive videos + with the new API + + So here we have to connect to Youtube to get this ID and update existing channels*/ + (function upgradeChannels(iii) { + id = ExtensionData.channels[iii].id; + name = ExtensionData.channels[iii].name; + + id = (iii > 0) ? 'UC' + id : id; //we need to add 'UC' to our old channel ids except for the first channel + + getYoutuber(id, function(response) { + if (response.statusText === "OK") { + channel = response.json.items[0]; + ExtensionData.channels[iii].uploadsPlayListId = channel.contentDetails.relatedPlaylists.uploads; + ExtensionData.channels[iii].id = id; + } else { + ExtensionData.channels[iii].uploadsPlayListId = null; + ExtensionData.channels[iii].id = id; + console.error('No uploads playlist id found'); + } + + if (iii < ExtensionData.channels.length - 1) { + return upgradeChannels(++iii); + } else { + DATA.save(ExtensionData); + init(ExtensionData); + return true; + } + + }, false); + })(0); + + } + + /* + @param string account - the account id OR playlist id #confusing? + @param function callback the callback function + @param bool getVideos - get or not video data + */ + function getYoutuber(account, callback, getVideos) { + //var url = 'http://gdata.youtube.com/feeds/api/users/' + account; + var url = 'https://www.googleapis.com/youtube/v3/'; + var params = { + 'part': 'snippet', + 'key': 'AIzaSyBbTkdQ5Pl_tszqJqdafAqF0mVWWngv9HU', + }; + //extra parameters needed to get account videos + if (getVideos) { + url += 'playlistItems'; + params.maxResults = 4; + params.playlistId = account; + params.fields = 'items(snippet,status)'; + } else { + params.id = account; + params.part += ',contentDetails'; + url += 'channels'; + } + + Request({ + url: url, + headers: { + 'Cache-control': 'no-cache' + }, + content: params, + onComplete: function(response) { + callback(response); + }, + }).get(); + } + +} ); }, 1000); \ No newline at end of file diff --git a/Firefox/my-youtube.xpi b/Firefox/my-youtube.xpi index f8a5a64..7f8d068 100644 Binary files a/Firefox/my-youtube.xpi and b/Firefox/my-youtube.xpi differ diff --git a/Firefox/package.json b/Firefox/package.json index bbcd3aa..23986d8 100644 --- a/Firefox/package.json +++ b/Firefox/package.json @@ -10,9 +10,9 @@ "title": "My Youtube", "id": "MyYoutube@ManlyBytes.com", "description": "Never miss another video of your favorite Youtubers", - "author": "Juanix.net", + "author": "OverStruck (Juanix.net OverStruck.com)", "license": "GNU V2", - "version": "1.3.1", + "version": "1.3.2 beta", "icon": "data//icons//icon48.png", "permissions": {