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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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": {