[READ-ONLY] Mirror of https://github.com/probablykasper/LaRSS. RSS Generator for iTunes larss.kasper.space
rss website
0

Configure Feed

Select the types of activity you want to include in your feed.

LaRSS / docs / index.js
19 kB 482 lines
1window.xhr = function(req, options) { 2 // handle options passed as first argument 3 if (options === undefined) { 4 options = req; 5 if (options.req) req = options.req; 6 else if (options.json) req = JSON.stringify(options.json); 7 } 8 9 // init xhr 10 if (!options.url) return "url required"; 11 if (!options.type) options.type = "POST"; 12 if (!options.contentType) options.contentType = "application/x-www-form-urlencoded"; 13 14 // initiate & send request 15 var xhr = new XMLHttpRequest(); 16 xhr.open(options.type, options.url, true); 17 xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded"); 18 if (options.auth) xhr.setRequestHeader("Authorization", options.auth); 19 if (options.headers) { 20 for (var i = 0; i < options.headers.length; i++) { 21 xhr.setRequestHeader(options.headers[i][0], options.headers[i][1]); 22 } 23 } 24 xhr.send(req); 25 26 // handle response 27 xhr.onreadystatechange = function() { 28 if (this.readyState == 4) { 29 if (String(this.status).startsWith(2)) { 30 if (options.callback) options.callback(this.responseText, false); 31 if (options.onSuccess) options.onSuccess(this.responseText, this.status); 32 } else { 33 if (options.callback) options.callback(this.responseText, this.status); 34 if (options.onError) options.onError(this.responseText, this.status); 35 } 36 } 37 }; 38}; 39 40(function items() { 41 document.addEventListener("click", function(e) { 42 // collapse 43 if (e.target.classList.contains("collapse-icon")) { 44 var item = e.target.parentElement.parentElement; 45 item.classList.toggle("collapsed"); 46 } 47 // add 48 if (e.target.classList.contains("add-icon")) { 49 var item = document.querySelector(".container-sample .item").cloneNode(true); 50 var container = document.querySelector(".container"); 51 container.insertBefore(item, document.querySelector(".container .item")); 52 var textareas = item.querySelectorAll("textarea"); 53 for (var i = 0; i < textareas.length; i++) { 54 resizeTextarea(textareas[i]); 55 } 56 } 57 // delete 58 if (e.target.classList.contains("delete-icon")) { 59 var item = e.target.parentElement.parentElement; 60 item.parentElement.removeChild(item); 61 } 62 }); 63 document.addEventListener("input", function(e) { 64 if (e.target.classList.contains("title")) { 65 var item = e.target.parentElement.parentElement.parentElement; 66 if (item.classList.contains("item")) { 67 item.querySelector(".item-title").innerHTML = e.target.value; 68 } 69 } 70 }); 71})(); 72 73(function textareaResize() { 74 window.resizeTextarea = function(textarea) { 75 textarea.style.height = "auto"; 76 textarea.parentElement.style.height = "auto"; 77 var newHeight = textarea.scrollHeight; 78 var cs = window.getComputedStyle(textarea); // cs == computedStyles 79 var padding = Number(cs.paddingTop.slice(0, -2)) + Number(cs.paddingBottom.slice(0, -2)); 80 textarea.style.height = newHeight+"px"; 81 } 82 window.resizeTextareas = function() { 83 var textareas = document.querySelectorAll("textarea"); 84 for (var i = 0; i < textareas.length; i++) { 85 resizeTextarea(textareas[i]); 86 } 87 } 88 resizeTextareas(); 89 document.addEventListener("input", function(e) { 90 if (e.target.tagName == "TEXTAREA") { 91 resizeTextarea(e.target); 92 } 93 }); 94})(); 95 96var pat = localStorage.getItem("pat"); 97var gistId = localStorage.getItem("gistId"); 98function getFilename(pat) { 99 return { 100 json: "LaRSS-"+pat.slice(0,4)+".json", 101 rss: "LaRSS-"+pat.slice(0,4)+".rss" 102 }; 103} 104 105load(pat); 106function load(pat, callback) { 107 if (pat) { 108 // if gistId is already saved, load it. Otherwise, find the gistId 109 if (gistId) { 110 findGist(pat, gistId, function(content, rssURL) { 111 // if the gist was found, load it. Otherwise 112 if (content) { 113 gistFound(content, rssURL); 114 if (callback) callback(); 115 } else { 116 findGistId(pat, function(id) { 117 if (id) { 118 findGist(pat, id, function(content, rssURL) { 119 gistFound(content, rssURL); 120 if (callback) callback(); 121 resizeTextareas(); 122 }); 123 } else { 124 createGist(pat, function(id, content, rssURL) { 125 localStorage.setItem("gistId", id); 126 gistId = id; 127 gistFound(content, rssURL); 128 if (callback) callback(); 129 }); 130 } 131 }); 132 } 133 }); 134 } else { 135 findGistId(pat, function(id) { 136 if (id) { 137 findGist(pat, id, function(content, rssURL) { 138 gistFound(content, rssURL); 139 if (callback) callback(); 140 resizeTextareas(); 141 }); 142 } else { 143 createGist(pat, function(id, content, rssURL) { 144 localStorage.setItem("gistId", id); 145 gistId = id; 146 gistFound(content, rssURL); 147 if (callback) callback(); 148 }); 149 } 150 }); 151 } 152 } else { 153 showPATdialog(); 154 } 155} 156function getGistPermaLink(old) { 157 var start = old.indexOf("/raw/") + 4; 158 var end = old.indexOf("/LaRSS"); 159 return old.slice(0, start)+old.slice(end); 160} 161function gistFound(json, rssURL) { 162 rssURL = getGistPermaLink(rssURL); 163 var container = document.querySelector(".container"); 164 container.innerHTML = '<button class="save-button">Save</button>'; 165 container.innerHTML += '<a target="_blank" href="'+rssURL+'"><button class="rss-link">RSS Link</button></a>'; 166 container.innerHTML += '<img src="logo.png" class="logo">'; 167 var gi = document.querySelector(".container-sample .general-info").cloneNode(true); // generalInfo 168 var gio = json.generalInfo; // generalInfoObject 169 var ia = json.items; // itemsArray 170 container.appendChild(gi); 171 gi.querySelector("input.title").value = gio.title; 172 gi.querySelector("input.author").value = gio.author; 173 gi.querySelector("input.subtitle").value = gio.subtitle; 174 gi.querySelector("textarea.description").value = gio.description; 175 gi.querySelector("input.link").value = gio.link; 176 gi.querySelector("input.imageURL").value = gio.imageURL; 177 gi.querySelector('select.language').value = gio.language; 178 gi.querySelector('select.category').value = gio.category; 179 gi.querySelector('select.explicit').value = gio.explicit; 180 gi.querySelector("input.copyright").value = gio.copyright; 181 gi.querySelector("input.name").value = gio.name; 182 gi.querySelector("input.email").value = gio.email; 183 for (var i = 0; i < json.items.length; i++) { 184 var item = document.querySelector(".container-sample .item").cloneNode(true); 185 container.appendChild(item); 186 item.querySelector("input.guid").value = ia[i].guid; 187 item.querySelector("input.title").value = ia[i].title; 188 item.querySelector("h3.item-title").innerHTML = ia[i].title; 189 item.querySelector("input.audioURL").value = ia[i].audioURL; 190 item.querySelector("input.imageURL").value = ia[i].imageURL; 191 item.querySelector('select.explicit').value = ia[i].explicit; 192 item.querySelector("input.date").value = ia[i].date; 193 item.querySelector("input.duration").value = ia[i].duration; 194 item.querySelector("textarea.summary").value = ia[i].summary; 195 } 196 resizeTextareas(); 197} 198 199function save(callback) { 200 var container = document.querySelector(".container"); 201 var gi = container.querySelector(".general-info"); // generalInfo 202 var gio = {}; // generalInfoObject 203 gio.title = gi.querySelector("input.title").value; 204 gio.author = gi.querySelector("input.author").value; 205 gio.subtitle = gi.querySelector("input.subtitle").value; 206 gio.description = gi.querySelector("textarea.description").value; 207 gio.link = gi.querySelector("input.link").value; 208 gio.imageURL = gi.querySelector("input.imageURL").value; 209 gio.language = gi.querySelector('select.language').value; 210 gio.category = gi.querySelector('select.category').value; 211 gio.explicit = gi.querySelector('select.explicit').value; 212 gio.copyright = gi.querySelector("input.copyright").value; 213 gio.name = gi.querySelector("input.name").value; 214 gio.email = gi.querySelector("input.email").value; 215 216 var items = container.querySelectorAll(".item"); // generalInfo 217 var ia = []; // itemsArray 218 for (var i = 0; i < items.length; i++) { 219 ia[i] = {}; 220 ia[i].guid = items[i].querySelector("input.guid").value 221 ia[i].title = items[i].querySelector("input.title").value 222 ia[i].title = items[i].querySelector("h3.item-title").innerHTML 223 ia[i].audioURL = items[i].querySelector("input.audioURL").value 224 ia[i].imageURL = items[i].querySelector("input.imageURL").value 225 ia[i].explicit = items[i].querySelector('select.explicit').value 226 ia[i].date = items[i].querySelector("input.date").value 227 ia[i].duration = items[i].querySelector("input.duration").value 228 ia[i].summary = items[i].querySelector("textarea.summary").value 229 } 230 var json = { 231 generalInfo: gio, 232 items: ia 233 }; 234 var xml = generateXML(json); 235 updateGist(gistId, json, xml, function(id) { 236 if (id) { 237 console.log("saved"); 238 if (callback) callback(true); 239 } else { 240 console.log("not saved"); 241 if (callback) callback(false); 242 } 243 }); 244} 245 246function updateGist(gistId, json, xml, callback) { 247 var req = { 248 files: {} 249 }; 250 req.files[getFilename(pat).json] = { 251 content: JSON.stringify(json) 252 }; 253 req.files[getFilename(pat).rss] = { 254 content: xml 255 }; 256 xhr({ 257 url: "https://api.github.com/gists/"+gistId, 258 auth: "token "+pat, 259 type: "POST", 260 json: req, 261 onSuccess: function(res) { 262 res = JSON.parse(res); 263 console.log("----------------------------------- updateGist suc"); 264 console.log(res); 265 callback(res.id, new Date(res.updated_at)); 266 }, 267 onError: function(res, code) { 268 res = JSON.parse(res); 269 console.log("----------------------------------- updateGist err"); 270 console.log(code); 271 console.log(res); 272 callback(false); 273 } 274 }); 275} 276 277document.addEventListener("click", function(e) { 278 if (e.target.classList.contains("save-button")) { 279 e.target.classList.add("saving"); 280 e.target.innerHTML = "Saving..."; 281 save(function(success) { 282 if (success) { 283 e.target.classList.remove("saving"); 284 e.target.classList.add("saved"); 285 e.target.innerHTML = "Saved"; 286 setTimeout(function() { 287 e.target.classList.remove("saved"); 288 e.target.innerHTML = "Save"; 289 },3000); 290 } else { 291 e.target.classList.remove("saving"); 292 e.target.classList.add("error"); 293 e.target.innerHTML = "Error saving :l"; 294 } 295 }); 296 } 297}); 298 299function showPATdialog() { 300 var dialog = document.querySelector(".pat-dialog"); 301 dialog.classList.add("visible"); 302} 303(function patDialog() { 304 var button = document.querySelector(".pat-settings"); 305 var dialog = document.querySelector(".pat-dialog"); 306 var patInput = dialog.querySelector("input.pat"); 307 if (pat) patInput.value = pat; 308 button.addEventListener("click", function(e) { 309 showPATdialog(); 310 }); 311 var saveButton = dialog.querySelector("button.save-pat"); 312 saveButton.addEventListener("click", function() { 313 console.log("saving access token"); 314 // save personal access token 315 pat = patInput.value; 316 localStorage.setItem("pat", pat); 317 jsonGistId = null; 318 rssGistId = null; 319 localStorage.removeItem("gistId"); 320 dialog.classList.add("saving"); 321 load(pat, function() { 322 dialog.classList.remove("saving"); 323 dialog.classList.remove("visible"); 324 }); 325 }); 326 document.addEventListener("click", function(e) { 327 if (e.target.classList.contains("dialog-container")) { 328 e.target.classList.remove("visible"); 329 } 330 }); 331})(); 332 333function findGist(pat, gistId, callback) { 334 xhr({ 335 url: "https://api.github.com/gists/"+gistId, 336 auth: "token "+pat, 337 type: "GET", 338 req: "", 339 onSuccess: function(gist) { 340 gist = JSON.parse(gist); 341 console.log("----------------------------------- findGist suc"); 342 console.log(gist); 343 var jsonFile = gist.files[getFilename(pat).json]; 344 var rssFile = gist.files[getFilename(pat).rss]; 345 callback(JSON.parse(jsonFile.content), rssFile.raw_url); 346 }, 347 onError: function(res, code) { 348 res = JSON.parse(res); 349 console.log("----------------------------------- findGist err"); 350 console.log(code); 351 console.log(res); 352 callback(false); 353 } 354 }); 355} 356 357function generateXML(json) { 358 var xml = ''; 359 xml += '<?xml version="1.0" encoding="UTF-8"?>\n'; 360 xml += '<rss version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd">\n'; 361 xml += ' <channel>\n'; 362 xml += ' <title>' +json.generalInfo.title+ '</title>\n'; 363 xml += ' <link>' +json.generalInfo.link+ '</link>\n'; 364 xml += ' <language>' +json.generalInfo.language+ '</language>\n'; 365 xml += ' <copyright>' +json.generalInfo.copyright+ '</copyright>\n'; 366 xml += ' <itunes:subtitle>' +json.generalInfo.subtitle+ '</itunes:subtitle>\n'; 367 xml += ' <itunes:author>' +json.generalInfo.author+ '</itunes:author>\n'; 368 xml += ' <description>' +json.generalInfo.description+ '</description>\n'; 369 xml += ' <itunes:owner>\n'; 370 xml += ' <itunes:name>' +json.generalInfo.name+ '</itunes:name>\n'; 371 xml += ' <itunes:email>' +json.generalInfo.email+ '</itunes:email>\n'; 372 xml += ' </itunes:owner>\n'; 373 xml += ' <itunes:image href="' +json.generalInfo.imageURL+ '"/>\n'; 374 xml += ' <itunes:category text="'+json.generalInfo.category+ '"/>\n'; 375 xml += ' <itunes:explicit>' +json.generalInfo.explicit+ '</itunes:explicit>\n'; 376 377 for (var i = 0; i < json.items.length; i++) { 378 xml += ' <item>\n'; 379 xml += ' <title>' +json.items[i].title+ '</title>\n'; 380 xml += ' <itunes:summary>' +json.items[i].summary+ '</itunes:summary>\n'; 381 xml += ' <itunes:image href="' +json.items[i].imageURL+ '"/>\n'; 382 xml += ' <enclosure type="audio/mpeg" url="' +json.items[i].audioURL+ '" length="0"/>\n'; 383 xml += ' <guid>' +json.items[i].guid+ '</guid>\n'; 384 xml += ' <pubDate>' +json.items[i].date+ '</pubDate>\n'; 385 xml += ' <itunes:duration>' +json.items[i].duration+ '</itunes:duration>\n'; 386 xml += ' <itunes:explicit>' +json.items[i].explicit+ '</itunes:explicit>\n'; 387 xml += ' </item>\n'; 388 } 389 390 xml += ' </channel>\n'; 391 xml += '</rss>\n'; 392 return xml; 393} 394 395function createGist(pat, callback) { 396 var req = { 397 description: "RSS Gist created by LaRSS", 398 files: {} 399 }; 400 var defaultJSON = { 401 generalInfo: { 402 title: "", 403 author: "", 404 subtitle: "", 405 description: "", 406 link: "", 407 imageURL: "", 408 explicit: "no", 409 language: "en-us", 410 category: "Music", 411 copyright: "", 412 name: "", 413 email: "" 414 }, 415 items: [ 416 { 417 guid: "", 418 title: "New Item", 419 audioURL: "", 420 imageURL: "", 421 explicit: "no", 422 date: "Wed, 25 Oct 2017 22:00:00 CET", 423 duration: "", 424 summary: "" 425 } 426 ] 427 }; 428 req.files[getFilename(pat).json] = { 429 content: JSON.stringify(defaultJSON) 430 }; 431 req.files[getFilename(pat).rss] = { 432 content: "empty rn" 433 }; 434 xhr({ 435 url: "https://api.github.com/gists", 436 auth: "token "+pat, 437 type: "POST", 438 json: req, 439 onSuccess: function(gist) { 440 gist = JSON.parse(gist); 441 console.log("----------------------------------- createGist suc"); 442 console.log(gist); 443 var rssFile = gist.files[getFilename(pat).rss]; 444 callback(gist.id, defaultJSON, rssFile.raw_url); 445 }, 446 onError: function(res, code) { 447 res = JSON.parse(res); 448 console.log("----------------------------------- createGist err"); 449 console.log(code); 450 console.log(res); 451 } 452 }); 453} 454 455function findGistId(pat, callback) { 456 xhr({ 457 url: "https://api.github.com/gists", 458 auth: "token "+pat, 459 type: "GET", 460 req: "", 461 onSuccess: function(gists) { 462 gists = JSON.parse(gists); 463 console.log("----------------------------------- findgistid suc"); 464 console.log(gists); 465 for (var i = 0; i < gists.length; i++) { 466 if (gists[i].files[getFilename(pat).json]) { 467 callback(gists[i].id); 468 localStorage.setItem("gistId", gists[i].id); 469 return; 470 } 471 } 472 callback(false); 473 }, 474 onError: function(res, code) { 475 res = JSON.parse(res); 476 console.log("----------------------------------- findgistid err"); 477 console.log(code); 478 console.log(res); 479 callback(false); 480 } 481 }); 482}