sb.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. var DEFAULT_DELAY = 20;
  2. var ACCOUNT_ID = "133328";
  3. var Countdown = {
  4. _timeout: null,
  5. _stepCb: null,
  6. _timeoutCb: null,
  7. running: false,
  8. seconds: DEFAULT_DELAY,
  9. _initial_seconds: DEFAULT_DELAY,
  10. start: function(seconds, timeoutCb, stepCb) {
  11. Countdown.stop();
  12. Countdown.seconds = Countdown._initial_seconds = seconds || DEFAULT_DELAY;
  13. Countdown._timeoutCb = timeoutCb || Countdown._timeoutCb;
  14. Countdown._stepCb = stepCb || Countdown._stepCb;
  15. Countdown.running = true;
  16. Countdown._step();
  17. },
  18. stop: function() {
  19. if (Countdown._timeout) {
  20. window.clearTimeout(Countdown._timeout);
  21. }
  22. Countdown.running = false;
  23. },
  24. restart: function() {
  25. Countdown.start(Countdown._initial_seconds);
  26. },
  27. _step: function() {
  28. if (Countdown._stepCb) {
  29. Countdown._stepCb();
  30. }
  31. if (Countdown.seconds === 0) {
  32. if (Countdown._timeoutCb) {
  33. Countdown._timeoutCb();
  34. }
  35. Countdown.stop();
  36. } else {
  37. Countdown._decrement();
  38. }
  39. },
  40. _decrement: function() {
  41. Countdown.seconds = Countdown.seconds - 1;
  42. Countdown._timeout = window.setTimeout(function() {
  43. Countdown._step();
  44. }, 1000);
  45. }
  46. };
  47. function uuidv4() {
  48. return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
  49. (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
  50. );
  51. }
  52. var UUID = uuidv4();
  53. function getWSPath() {
  54. var loc = window.location, new_uri;
  55. if (loc.protocol === "https:") {
  56. new_uri = "wss:";
  57. } else {
  58. new_uri = "ws:";
  59. }
  60. new_uri += "//" + loc.host + "/ws?uuid=" + UUID;
  61. return new_uri;
  62. }
  63. var WS = new WebSocket(getWSPath());
  64. WS.onerror = function(error) {
  65. console.log('WebSocket Error ' + error);
  66. };
  67. WS.onmessage = function(e) {
  68. console.log("received message on websocket: " + e.data);
  69. var jdata = JSON.parse(e.data);
  70. if (!(jdata && jdata.source == "button" && jdata.action == "clicked")) {
  71. return;
  72. }
  73. if (!Countdown.running) {
  74. takePhoto("press again to publish!");
  75. } else {
  76. sendPhoto();
  77. }
  78. };
  79. function runCamera(stream) {
  80. console.log("initialize the camera");
  81. var video = document.querySelector("#sb-video");
  82. var container = document.querySelector("#canvas-container");
  83. container.width = video.videoWidth;
  84. video.onloadedmetadata = function() {
  85. video.play();
  86. };
  87. video.srcObject = stream;
  88. resizeCanvas(video, 'sb-canvas');
  89. }
  90. function sendData(data) {
  91. var formData = new FormData();
  92. var msg = "";
  93. formData.append("selfie", new Blob([data]), "selfie.jpeg");
  94. fetch("/publish/", {
  95. method: "POST",
  96. body: formData
  97. }).then(function(response) {
  98. if (response.status !== 200) {
  99. msg = response.status;
  100. console.log(msg);
  101. iziToast.error({
  102. "title": "😭 something wrong sending the data 😭",
  103. "target": "#izi-container",
  104. "message": msg,
  105. "titleSize": "3em",
  106. "messageSize": "2em",
  107. "close": false,
  108. "drag": false,
  109. "pauseOnHover": false,
  110. "progressBarColor": "red",
  111. "position": "topCenter"
  112. });
  113. }
  114. cancelPhoto();
  115. return response.json();
  116. }).then(function(json) {
  117. json = json || {};
  118. console.log(json);
  119. if (json && json.success) {
  120. msg = "❤ ❤ ❤ photo sent successfully! ❤ ❤ ❤";
  121. console.log(msg);
  122. iziToast.destroy();
  123. iziToast.success({
  124. "title": msg,
  125. "target": "#izi-container",
  126. "titleSize": "3em",
  127. "messageSize": "2em",
  128. "close": false,
  129. "drag": false,
  130. "pauseOnHover": false,
  131. "progressBarColor": "red",
  132. "position": "topCenter"
  133. });
  134. updateFeed();
  135. } else {
  136. msg = json.message;
  137. console.log(msg);
  138. iziToast.error({
  139. "title": "😭 backend error 😭",
  140. "target": "#izi-container",
  141. "message": msg,
  142. "titleSize": "3em",
  143. "messageSize": "2em",
  144. "close": false,
  145. "drag": false,
  146. "pauseOnHover": false,
  147. "progressBarColor": "red",
  148. "position": "topCenter"
  149. });
  150. }
  151. }).catch(function(err) {
  152. console.log(err);
  153. iziToast.error({
  154. "title": "😭 error connecting to the server 😭",
  155. "target": "#izi-container",
  156. "message": err,
  157. "titleSize": "3em",
  158. "messageSize": "2em",
  159. "close": false,
  160. "drag": false,
  161. "pauseOnHover": false,
  162. "progressBarColor": "red",
  163. "position": "topCenter"
  164. });
  165. cancelPhoto();
  166. });
  167. }
  168. function cancelPhoto(clearToast) {
  169. console.log("cancel photo");
  170. document.querySelector("#send-photo-btn").classList.add("disabled");
  171. document.querySelector("#cancel-photo-btn").classList.add("disabled");
  172. var canvas = document.querySelector("#sb-canvas");
  173. var context = canvas.getContext("2d");
  174. context.clearRect(0, 0, canvas.width, canvas.height);
  175. Countdown.stop();
  176. if (clearToast) {
  177. iziToast.destroy();
  178. }
  179. }
  180. function isBlank(canvas) {
  181. var blank = document.createElement("canvas");
  182. blank.width = canvas.width;
  183. blank.height = canvas.height;
  184. return canvas.toDataURL() == blank.toDataURL();
  185. }
  186. function sendPhoto() {
  187. console.log("send photo");
  188. Countdown.stop();
  189. var canvas = document.querySelector("#sb-canvas");
  190. if (!canvas || isBlank(canvas)) {
  191. var msg = "I cowardly refuse to send a blank image.";
  192. console.log(msg);
  193. iziToast.warning({
  194. "title": msg,
  195. "target": "#izi-container",
  196. "titleSize": "3em",
  197. "messageSize": "2em",
  198. "close": false,
  199. "drag": false,
  200. "pauseOnHover": false,
  201. "progressBarColor": "red",
  202. "position": "topCenter"
  203. });
  204. return;
  205. }
  206. return sendData(canvas.toDataURL("image/jpeg"));
  207. }
  208. function _takePhoto(message) {
  209. console.log("take photo");
  210. var video = document.querySelector("#sb-video");
  211. if (!(video.offsetWidth && video.offsetHeight)) {
  212. var msg = "missing video";
  213. console.log(msg);
  214. iziToast.warning({
  215. "title": msg,
  216. "target": "#izi-container",
  217. "message": "please grant camera permissions",
  218. "titleSize": "3em",
  219. "messageSize": "2em",
  220. "close": false,
  221. "drag": false,
  222. "pauseOnHover": false,
  223. "progressBarColor": "red",
  224. "position": "topCenter"
  225. });
  226. return;
  227. }
  228. var canvas = document.querySelector("#sb-canvas");
  229. var context = canvas.getContext("2d");
  230. canvas.width = video.offsetWidth;
  231. canvas.height = video.offsetHeight;
  232. /*
  233. var tmpCanvas = document.createElement("canvas");
  234. tmpCanvas.width = video.offsetWidth;
  235. tmpCanvas.height = video.offsetHeight;
  236. var tmpContext = tmpCanvas.getContext("2d");
  237. var tmpRatio = (tmpCanvas.height / tmpCanvas.width);
  238. tmpContext.drawImage(video, 0, 0, video.offsetWidth, video.offsetHeight);
  239. canvas.width = canvas.offsetWidth;
  240. canvas.height = canvas.offsetHeight;
  241. canvas.style.height = parseInt(canvas.offsetWidth * tmpRatio);
  242. var scale = canvas.width / tmpCanvas.width;
  243. context.scale(scale, scale);
  244. context.drawImage(tmpCanvas, 0, 0);
  245. */
  246. context.drawImage(video, 0, 0, video.offsetWidth, video.offsetHeight);
  247. document.querySelector("#send-photo-btn").classList.remove("disabled");
  248. document.querySelector("#cancel-photo-btn").classList.remove("disabled");
  249. iziToast.question({
  250. "title": "do you like it?",
  251. "timeout": DEFAULT_DELAY * 1000,
  252. "target": "#izi-container",
  253. "message": message || "press \"share photo\" to publish!",
  254. "titleSize": "3em",
  255. "messageSize": "2em",
  256. "close": false,
  257. "drag": false,
  258. "pauseOnHover": false,
  259. "progressBarColor": "red",
  260. "position": "topCenter"
  261. });
  262. Countdown.start(DEFAULT_DELAY, cancelPhoto);
  263. }
  264. function takePhoto(msg) {
  265. _takePhoto(msg);
  266. // in case we need to introduce a delay:
  267. // window.setTimeout(function() { _takePhoto(msg); }, 1000);
  268. }
  269. function loadMedia(url) {
  270. fetch(url)
  271. .then((response) => response.text())
  272. .then((jdata) => {
  273. var data = JSON.parse(jdata);
  274. var imgCont = document.getElementById("images-container");
  275. imgCont.innerHTML = "";
  276. for (var i = 0 ; i < data.length; i++) {
  277. var elem = data[i];
  278. if (!(elem.media_attachments && elem.media_attachments.length > 0)) {
  279. continue;
  280. }
  281. var imgData = elem.media_attachments[0];
  282. if (imgData.type != "image" || !imgData.preview_url) {
  283. continue;
  284. }
  285. var imgUrl = imgData.preview_url;
  286. imgCont.innerHTML += "<p><img class=\"feed-images\" src=" + imgUrl + "></p>";
  287. }
  288. })
  289. .catch((error) => {
  290. console.warn(error);
  291. });
  292. }
  293. function updateFeed() {
  294. loadMedia("https://chaos.social/api/v1/accounts/" + ACCOUNT_ID + "/statuses");
  295. }
  296. function initCamera() {
  297. console.log("request camera permission");
  298. document.querySelector("#canvas-container").style.display = "block";
  299. var videoObj = {
  300. "video": {
  301. width: 800,
  302. height: 600
  303. },
  304. "audio": false
  305. };
  306. navigator.mediaDevices.getUserMedia(videoObj).then(function(stream) {
  307. runCamera(stream);
  308. document.querySelector("#init-btn").style.display = "none";
  309. document.querySelector("#take-photo-btn").classList.remove("disabled");
  310. }).catch(function(err) {
  311. console.log("unable to open camera");
  312. console.log(err);
  313. iziToast.error({
  314. "title": "unable to open camera",
  315. "message": "please reload this page: " + err,
  316. "titleSize": "3em",
  317. "messageSize": "2em",
  318. "close": false,
  319. "drag": false,
  320. "pauseOnHover": false,
  321. "progressBarColor": "red",
  322. "position": "topCenter"
  323. });
  324. });
  325. }
  326. function resizeCanvas(el, canvasID) {
  327. var canvas = document.getElementById(canvasID);
  328. canvas.width = el.offsetWidth;
  329. canvas.height = el.offsetHeighth;
  330. }
  331. window.onload = function(e) {
  332. updateFeed();
  333. }