ApiClient.js 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936
  1. (function (jQuery, window, undefined) {
  2. "use strict";
  3. var matched, browser;
  4. jQuery.uaMatch = function (ua) {
  5. ua = ua.toLowerCase();
  6. var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
  7. /(webkit)[ \/]([\w.]+)/.exec(ua) ||
  8. /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
  9. /(msie) ([\w.]+)/.exec(ua) ||
  10. ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
  11. [];
  12. var platform_match = /(ipad)/.exec(ua) ||
  13. /(iphone)/.exec(ua) ||
  14. /(android)/.exec(ua) ||
  15. [];
  16. return {
  17. browser: match[1] || "",
  18. version: match[2] || "0",
  19. platform: platform_match[0] || ""
  20. };
  21. };
  22. matched = jQuery.uaMatch(window.navigator.userAgent);
  23. browser = {};
  24. if (matched.browser) {
  25. browser[matched.browser] = true;
  26. browser.version = matched.version;
  27. }
  28. if (matched.platform) {
  29. browser[matched.platform] = true
  30. }
  31. // Chrome is Webkit, but Webkit is also Safari.
  32. if (browser.chrome) {
  33. browser.webkit = true;
  34. } else if (browser.webkit) {
  35. browser.safari = true;
  36. }
  37. jQuery.browser = browser;
  38. })(jQuery, window);
  39. if (!window.MediaBrowser) {
  40. window.MediaBrowser = {};
  41. }
  42. MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
  43. /**
  44. * Creates a new api client instance
  45. * @param {String} serverProtocol
  46. * @param {String} serverHostName
  47. * @param {String} serverPortNumber
  48. * @param {String} clientName
  49. */
  50. return function (serverProtocol, serverHostName, serverPortNumber, clientName) {
  51. var self = this;
  52. var deviceName = "Web Browser";
  53. var deviceId = MediaBrowser.SHA1(navigator.userAgent + (navigator.cpuClass || ""));
  54. var currentUserId;
  55. var webSocket;
  56. /**
  57. * Gets the server host name.
  58. */
  59. self.serverHostName = function () {
  60. return serverHostName;
  61. };
  62. /**
  63. * Gets the server port number.
  64. */
  65. self.serverPortNumber = function () {
  66. return serverPortNumber;
  67. };
  68. /**
  69. * Gets or sets the current user id.
  70. */
  71. self.currentUserId = function (val) {
  72. if (val !== undefined) {
  73. currentUserId = val;
  74. } else {
  75. return currentUserId;
  76. }
  77. };
  78. deviceName = (function () {
  79. var name = "";
  80. if ($.browser.chrome) {
  81. name = "Chrome";
  82. }
  83. else if ($.browser.safari) {
  84. name = "Safari";
  85. }
  86. else if ($.browser.webkit) {
  87. name = "WebKit";
  88. }
  89. else if ($.browser.msie) {
  90. name = "Internet Explorer";
  91. }
  92. else if ($.browser.firefox) {
  93. name = "Firefox";
  94. }
  95. else if ($.browser.mozilla) {
  96. name = "Firefox";
  97. }
  98. else if ($.browser.opera) {
  99. name = "Opera";
  100. }
  101. else {
  102. name = "Web Browser";
  103. }
  104. if ($.browser.ipad) {
  105. name += " Ipad";
  106. }
  107. else if ($.browser.iphone) {
  108. name += " Iphone";
  109. }
  110. else if ($.browser.android) {
  111. name += " Android";
  112. }
  113. return name;
  114. }());
  115. /**
  116. * Wraps around jQuery ajax methods to add additional info to the request.
  117. */
  118. self.ajax = function (request) {
  119. if (!request) {
  120. throw new Error("Request cannot be null");
  121. }
  122. var auth = 'MediaBrowser Client="' + clientName + '", Device="' + deviceName + '", DeviceId="' + deviceId + '"';
  123. if (currentUserId) {
  124. auth += ', UserId="' + currentUserId + '"';
  125. }
  126. request.headers = {
  127. Authorization: auth
  128. };
  129. return $.ajax(request);
  130. };
  131. /**
  132. * Creates an api url based on a handler name and query string parameters
  133. * @param {String} name
  134. * @param {Object} params
  135. */
  136. self.getUrl = function (name, params) {
  137. if (!name) {
  138. throw new Error("Url name cannot be empty");
  139. }
  140. var url = serverProtocol + "//" + serverHostName + ":" + serverPortNumber + "/mediabrowser/" + name;
  141. if (params) {
  142. url += "?" + $.param(params);
  143. }
  144. return url;
  145. };
  146. self.openWebSocket = function (port) {
  147. var url = "ws://" + serverHostName + ":" + port + "/mediabrowser";
  148. webSocket = new WebSocket(url);
  149. webSocket.onmessage = function (msg) {
  150. msg = JSON.parse(msg.data);
  151. $(self).trigger("websocketmessage", [msg]);
  152. };
  153. webSocket.onopen = function () {
  154. setTimeout(function () {
  155. $(self).trigger("websocketopen");
  156. }, 500);
  157. };
  158. webSocket.onerror = function () {
  159. setTimeout(function () {
  160. $(self).trigger("websocketerror");
  161. }, 0);
  162. };
  163. webSocket.onclose = function () {
  164. setTimeout(function () {
  165. $(self).trigger("websocketclose");
  166. }, 0);
  167. };
  168. };
  169. self.sendWebSocketMessage = function (name, data) {
  170. var msg = { MessageType: name };
  171. if (data) {
  172. msg.Data = data;
  173. }
  174. msg = JSON.stringify(msg);
  175. webSocket.send(msg);
  176. };
  177. self.isWebSocketOpen = function () {
  178. return webSocket && webSocket.readyState === WebSocket.OPEN;
  179. };
  180. self.isWebSocketOpenOrConnecting = function () {
  181. return webSocket && (webSocket.readyState === WebSocket.OPEN || webSocket.readyState === WebSocket.CONNECTING);
  182. };
  183. /**
  184. * Gets an item from the server
  185. * Omit itemId to get the root folder.
  186. */
  187. self.getItem = function (userId, itemId) {
  188. if (!userId) {
  189. throw new Error("null userId");
  190. }
  191. var url = self.getUrl("Users/" + userId + "/Items/" + itemId);
  192. return self.ajax({
  193. type: "GET",
  194. url: url,
  195. dataType: "json"
  196. });
  197. };
  198. /**
  199. * Gets the root folder from the server
  200. */
  201. self.getRootFolder = function (userId) {
  202. return self.getItem(userId);
  203. };
  204. /**
  205. * Gets the current server status
  206. */
  207. self.getSystemInfo = function () {
  208. var url = self.getUrl("System/Info");
  209. return self.ajax({
  210. type: "GET",
  211. url: url,
  212. dataType: "json"
  213. });
  214. };
  215. /**
  216. * Gets all cultures known to the server
  217. */
  218. self.getCultures = function () {
  219. var url = self.getUrl("Localization/cultures");
  220. return self.ajax({
  221. type: "GET",
  222. url: url,
  223. dataType: "json"
  224. });
  225. };
  226. /**
  227. * Gets all countries known to the server
  228. */
  229. self.getCountries = function () {
  230. var url = self.getUrl("Localization/countries");
  231. return self.ajax({
  232. type: "GET",
  233. url: url,
  234. dataType: "json"
  235. });
  236. };
  237. /**
  238. * Gets plugin security info
  239. */
  240. self.getPluginSecurityInfo = function () {
  241. var url = self.getUrl("Plugins/SecurityInfo");
  242. return self.ajax({
  243. type: "GET",
  244. url: url,
  245. dataType: "json"
  246. });
  247. };
  248. /**
  249. * Gets the directory contents of a path on the server
  250. */
  251. self.getDirectoryContents = function (path, options) {
  252. if (!path) {
  253. throw new Error("null path");
  254. }
  255. options = options || {};
  256. options.path = path;
  257. var url = self.getUrl("Environment/DirectoryContents", options);
  258. return self.ajax({
  259. type: "GET",
  260. url: url,
  261. dataType: "json"
  262. });
  263. };
  264. /**
  265. * Gets a list of physical drives from the server
  266. */
  267. self.getDrives = function () {
  268. var url = self.getUrl("Environment/Drives");
  269. return self.ajax({
  270. type: "GET",
  271. url: url,
  272. dataType: "json"
  273. });
  274. };
  275. /**
  276. * Gets a list of network devices from the server
  277. */
  278. self.getNetworkDevices = function () {
  279. var url = self.getUrl("Environment/NetworkDevices");
  280. return self.ajax({
  281. type: "GET",
  282. url: url,
  283. dataType: "json"
  284. });
  285. };
  286. /**
  287. * Cancels a package installation
  288. */
  289. self.cancelPackageInstallation = function (installationId) {
  290. if (!installationId) {
  291. throw new Error("null installationId");
  292. }
  293. var url = self.getUrl("Packages/Installing/" + id);
  294. return self.ajax({
  295. type: "DELETE",
  296. url: url,
  297. dataType: "json"
  298. });
  299. };
  300. /**
  301. * Installs or updates a new plugin
  302. */
  303. self.installPlugin = function (name, updateClass, version) {
  304. if (!name) {
  305. throw new Error("null name");
  306. }
  307. if (!updateClass) {
  308. throw new Error("null updateClass");
  309. }
  310. var options = {
  311. updateClass: updateClass
  312. };
  313. if (version) {
  314. options.version = version;
  315. }
  316. var url = self.getUrl("Packages/Installed/" + name, options);
  317. return self.ajax({
  318. type: "POST",
  319. url: url
  320. });
  321. };
  322. /**
  323. * Instructs the server to perform a pending kernel reload or app restart.
  324. * If a restart is not currently required, nothing will happen.
  325. */
  326. self.performPendingRestart = function () {
  327. var url = self.getUrl("System/Restart");
  328. return self.ajax({
  329. type: "POST",
  330. url: url
  331. });
  332. };
  333. /**
  334. * Gets information about an installable package
  335. */
  336. self.getPackageInfo = function (name) {
  337. if (!name) {
  338. throw new Error("null name");
  339. }
  340. var url = self.getUrl("Packages/" + name);
  341. return self.ajax({
  342. type: "GET",
  343. url: url,
  344. dataType: "json"
  345. });
  346. };
  347. /**
  348. * Gets the latest available application update (if any)
  349. */
  350. self.getAvailableApplicationUpdate = function () {
  351. var url = self.getUrl("Packages/Updates", { PackageType: "System" });
  352. return self.ajax({
  353. type: "GET",
  354. url: url,
  355. dataType: "json"
  356. });
  357. };
  358. /**
  359. * Gets the latest available plugin updates (if any)
  360. */
  361. self.getAvailablePluginUpdates = function () {
  362. var url = self.getUrl("Packages/Updates", { PackageType: "UserInstalled" });
  363. return self.ajax({
  364. type: "GET",
  365. url: url,
  366. dataType: "json"
  367. });
  368. };
  369. /**
  370. * Gets the virtual folder for a view. Specify a userId to get a user view, or omit for the default view.
  371. */
  372. self.getVirtualFolders = function (userId) {
  373. var url = userId ? "Users/" + userId + "/VirtualFolders" : "Library/VirtualFolders";
  374. url = self.getUrl(url);
  375. return self.ajax({
  376. type: "GET",
  377. url: url,
  378. dataType: "json"
  379. });
  380. };
  381. /**
  382. * Gets all the paths of the locations in the physical root.
  383. */
  384. self.getPhysicalPaths = function () {
  385. var url = self.getUrl("Library/PhysicalPaths");
  386. return self.ajax({
  387. type: "GET",
  388. url: url,
  389. dataType: "json"
  390. });
  391. };
  392. /**
  393. * Gets the current server configuration
  394. */
  395. self.getServerConfiguration = function () {
  396. var url = self.getUrl("System/Configuration");
  397. return self.ajax({
  398. type: "GET",
  399. url: url,
  400. dataType: "json"
  401. });
  402. };
  403. /**
  404. * Gets the server's scheduled tasks
  405. */
  406. self.getScheduledTasks = function () {
  407. var url = self.getUrl("ScheduledTasks");
  408. return self.ajax({
  409. type: "GET",
  410. url: url,
  411. dataType: "json"
  412. });
  413. };
  414. /**
  415. * Starts a scheduled task
  416. */
  417. self.startScheduledTask = function (id) {
  418. if (!id) {
  419. throw new Error("null id");
  420. }
  421. var url = self.getUrl("ScheduledTasks/Running/" + id);
  422. return self.ajax({
  423. type: "POST",
  424. url: url
  425. });
  426. };
  427. /**
  428. * Gets a scheduled task
  429. */
  430. self.getScheduledTask = function (id) {
  431. if (!id) {
  432. throw new Error("null id");
  433. }
  434. var url = self.getUrl("ScheduledTasks/" + id);
  435. return self.ajax({
  436. type: "GET",
  437. url: url,
  438. dataType: "json"
  439. });
  440. };
  441. /**
  442. * Stops a scheduled task
  443. */
  444. self.stopScheduledTask = function (id) {
  445. if (!id) {
  446. throw new Error("null id");
  447. }
  448. var url = self.getUrl("ScheduledTasks/Running/" + id);
  449. return self.ajax({
  450. type: "DELETE",
  451. url: url,
  452. dataType: "json"
  453. });
  454. };
  455. /**
  456. * Gets the configuration of a plugin
  457. * @param {String} Id
  458. */
  459. self.getPluginConfiguration = function (id) {
  460. if (!id) {
  461. throw new Error("null Id");
  462. }
  463. var url = self.getUrl("Plugins/" + id + "/Configuration");
  464. return self.ajax({
  465. type: "GET",
  466. url: url,
  467. dataType: "json"
  468. });
  469. };
  470. /**
  471. * Gets a list of plugins that are available to be installed
  472. */
  473. self.getAvailablePlugins = function () {
  474. var url = self.getUrl("Packages", { PackageType: "UserInstalled" });
  475. return self.ajax({
  476. type: "GET",
  477. url: url,
  478. dataType: "json"
  479. });
  480. };
  481. /**
  482. * Uninstalls a plugin
  483. * @param {String} Id
  484. */
  485. self.uninstallPlugin = function (id) {
  486. if (!id) {
  487. throw new Error("null Id");
  488. }
  489. var url = self.getUrl("Plugins/" + id);
  490. return self.ajax({
  491. type: "DELETE",
  492. url: url,
  493. dataType: "json"
  494. });
  495. };
  496. /**
  497. * Removes a virtual folder from either the default view or a user view
  498. * @param {String} name
  499. */
  500. self.removeVirtualFolder = function (name, userId) {
  501. if (!name) {
  502. throw new Error("null name");
  503. }
  504. var url = userId ? "Users/" + userId + "/VirtualFolders" : "Library/VirtualFolders";
  505. url += "/" + name;
  506. url = self.getUrl(url);
  507. return self.ajax({
  508. type: "DELETE",
  509. url: url,
  510. dataType: "json"
  511. });
  512. };
  513. /**
  514. * Adds a virtual folder to either the default view or a user view
  515. * @param {String} name
  516. */
  517. self.addVirtualFolder = function (name, userId) {
  518. if (!name) {
  519. throw new Error("null name");
  520. }
  521. var url = userId ? "Users/" + userId + "/VirtualFolders" : "Library/VirtualFolders";
  522. url += "/" + name;
  523. url = self.getUrl(url);
  524. return self.ajax({
  525. type: "POST",
  526. url: url
  527. });
  528. };
  529. /**
  530. * Renames a virtual folder, within either the default view or a user view
  531. * @param {String} name
  532. */
  533. self.renameVirtualFolder = function (name, newName, userId) {
  534. if (!name) {
  535. throw new Error("null name");
  536. }
  537. var url = userId ? "Users/" + userId + "/VirtualFolders" : "Library/VirtualFolders";
  538. url += "/" + name + "/Name";
  539. url = self.getUrl(url, { newName: newName });
  540. return self.ajax({
  541. type: "POST",
  542. url: url
  543. });
  544. };
  545. /**
  546. * Adds an additional mediaPath to an existing virtual folder, within either the default view or a user view
  547. * @param {String} name
  548. */
  549. self.addMediaPath = function (virtualFolderName, mediaPath, userId) {
  550. if (!virtualFolderName) {
  551. throw new Error("null virtualFolderName");
  552. }
  553. if (!mediaPath) {
  554. throw new Error("null mediaPath");
  555. }
  556. var url = userId ? "Users/" + userId + "/VirtualFolders" : "Library/VirtualFolders";
  557. url += "/" + virtualFolderName + "/Paths";
  558. url = self.getUrl(url, { path: mediaPath });
  559. return self.ajax({
  560. type: "POST",
  561. url: url
  562. });
  563. };
  564. /**
  565. * Removes a media path from a virtual folder, within either the default view or a user view
  566. * @param {String} name
  567. */
  568. self.removeMediaPath = function (virtualFolderName, mediaPath, userId) {
  569. if (!virtualFolderName) {
  570. throw new Error("null virtualFolderName");
  571. }
  572. if (!mediaPath) {
  573. throw new Error("null mediaPath");
  574. }
  575. var url = userId ? "Users/" + userId + "/VirtualFolders" : "Library/VirtualFolders";
  576. url += "/" + virtualFolderName + "/Paths";
  577. url = self.getUrl(url, { path: mediaPath });
  578. return self.ajax({
  579. type: "DELETE",
  580. url: url,
  581. dataType: "json"
  582. });
  583. };
  584. /**
  585. * Deletes a user
  586. * @param {String} id
  587. */
  588. self.deleteUser = function (id) {
  589. if (!id) {
  590. throw new Error("null id");
  591. }
  592. var url = self.getUrl("Users/" + id);
  593. return self.ajax({
  594. type: "DELETE",
  595. url: url,
  596. dataType: "json"
  597. });
  598. };
  599. /**
  600. * Deletes a user image
  601. * @param {String} userId
  602. * @param {String} imageType The type of image to delete, based on the server-side ImageType enum.
  603. */
  604. self.deleteUserImage = function (userId, imageType) {
  605. if (!userId) {
  606. throw new Error("null userId");
  607. }
  608. if (!imageType) {
  609. throw new Error("null imageType");
  610. }
  611. var url = self.getUrl("Users/" + userId + "/Images/" + imageType);
  612. return self.ajax({
  613. type: "DELETE",
  614. url: url,
  615. dataType: "json"
  616. });
  617. };
  618. /**
  619. * Uploads a user image
  620. * @param {String} userId
  621. * @param {String} imageType The type of image to delete, based on the server-side ImageType enum.
  622. * @param {Object} file The file from the input element
  623. */
  624. self.uploadUserImage = function (userId, imageType, file) {
  625. if (!userId) {
  626. throw new Error("null userId");
  627. }
  628. if (!imageType) {
  629. throw new Error("null imageType");
  630. }
  631. if (!file || !file.type.match('image.*')) {
  632. throw new Error("File must be an image.");
  633. }
  634. var deferred = $.Deferred();
  635. var reader = new FileReader();
  636. reader.onerror = function () {
  637. deferred.reject();
  638. };
  639. reader.onabort = function () {
  640. deferred.reject();
  641. };
  642. // Closure to capture the file information.
  643. reader.onload = function (e) {
  644. var data = window.btoa(e.target.result);
  645. var url = self.getUrl("Users/" + userId + "/Images/" + imageType);
  646. self.ajax({
  647. type: "POST",
  648. url: url,
  649. data: data,
  650. contentType: "image/" + file.name.substring(file.name.lastIndexOf('.') + 1)
  651. }).done(function (result) {
  652. deferred.resolveWith(null, [result]);
  653. }).fail(function () {
  654. deferred.reject();
  655. });
  656. };
  657. // Read in the image file as a data URL.
  658. reader.readAsBinaryString(file);
  659. return deferred.promise();
  660. };
  661. /**
  662. * Gets the list of installed plugins on the server
  663. */
  664. self.getInstalledPlugins = function () {
  665. var url = self.getUrl("Plugins");
  666. return self.ajax({
  667. type: "GET",
  668. url: url,
  669. dataType: "json"
  670. });
  671. };
  672. /**
  673. * Gets a user by id
  674. * @param {String} id
  675. */
  676. self.getUser = function (id) {
  677. if (!id) {
  678. throw new Error("Must supply a userId");
  679. }
  680. var url = self.getUrl("Users/" + id);
  681. return self.ajax({
  682. type: "GET",
  683. url: url,
  684. dataType: "json"
  685. });
  686. };
  687. /**
  688. * Gets a studio
  689. */
  690. self.getStudio = function (name) {
  691. if (!name) {
  692. throw new Error("null name");
  693. }
  694. var url = self.getUrl("Studios/" + name);
  695. return self.ajax({
  696. type: "GET",
  697. url: url,
  698. dataType: "json"
  699. });
  700. };
  701. /**
  702. * Gets a genre
  703. */
  704. self.getGenre = function (name) {
  705. if (!name) {
  706. throw new Error("null name");
  707. }
  708. var url = self.getUrl("Genres/" + name);
  709. return self.ajax({
  710. type: "GET",
  711. url: url,
  712. dataType: "json"
  713. });
  714. };
  715. /**
  716. * Gets a year
  717. */
  718. self.getYear = function (year) {
  719. if (!year) {
  720. throw new Error("null year");
  721. }
  722. var url = self.getUrl("Years/" + year);
  723. return self.ajax({
  724. type: "GET",
  725. url: url,
  726. dataType: "json"
  727. });
  728. };
  729. /**
  730. * Gets a Person
  731. */
  732. self.getPerson = function (name) {
  733. if (!name) {
  734. throw new Error("null name");
  735. }
  736. var url = self.getUrl("Persons/" + name);
  737. return self.ajax({
  738. type: "GET",
  739. url: url,
  740. dataType: "json"
  741. });
  742. };
  743. /**
  744. * Gets weather info
  745. * @param {String} location - us zip code / city, state, country / city, country
  746. * Omit location to get weather info using stored server configuration value
  747. */
  748. self.getWeatherInfo = function (location) {
  749. var url = self.getUrl("weather", {
  750. location: location
  751. });
  752. return self.ajax({
  753. type: "GET",
  754. url: url,
  755. dataType: "json"
  756. });
  757. };
  758. /**
  759. * Gets all users from the server
  760. */
  761. self.getUsers = function () {
  762. var url = self.getUrl("users");
  763. return self.ajax({
  764. type: "GET",
  765. url: url,
  766. dataType: "json"
  767. });
  768. };
  769. /**
  770. * Gets all available parental ratings from the server
  771. */
  772. self.getParentalRatings = function () {
  773. var url = self.getUrl("Localization/ParentalRatings");
  774. return self.ajax({
  775. type: "GET",
  776. url: url,
  777. dataType: "json"
  778. });
  779. };
  780. /**
  781. * Gets a list of all available conrete BaseItem types from the server
  782. */
  783. self.getItemTypes = function (options) {
  784. var url = self.getUrl("Library/ItemTypes", options);
  785. return self.ajax({
  786. type: "GET",
  787. url: url,
  788. dataType: "json"
  789. });
  790. };
  791. /**
  792. * Constructs a url for a user image
  793. * @param {String} userId
  794. * @param {Object} options
  795. * Options supports the following properties:
  796. * width - download the image at a fixed width
  797. * height - download the image at a fixed height
  798. * maxWidth - download the image at a maxWidth
  799. * maxHeight - download the image at a maxHeight
  800. * quality - A scale of 0-100. This should almost always be omitted as the default will suffice.
  801. * For best results do not specify both width and height together, as aspect ratio might be altered.
  802. */
  803. self.getUserImageUrl = function (userId, options) {
  804. if (!userId) {
  805. throw new Error("null userId");
  806. }
  807. options = options || {
  808. };
  809. var url = "Users/" + userId + "/Images/" + options.type;
  810. if (options.index != null) {
  811. url += "/" + options.index;
  812. }
  813. // Don't put these on the query string
  814. delete options.type;
  815. delete options.index;
  816. return self.getUrl(url, options);
  817. };
  818. /**
  819. * Constructs a url for a person image
  820. * @param {String} name
  821. * @param {Object} options
  822. * Options supports the following properties:
  823. * width - download the image at a fixed width
  824. * height - download the image at a fixed height
  825. * maxWidth - download the image at a maxWidth
  826. * maxHeight - download the image at a maxHeight
  827. * quality - A scale of 0-100. This should almost always be omitted as the default will suffice.
  828. * For best results do not specify both width and height together, as aspect ratio might be altered.
  829. */
  830. self.getPersonImageUrl = function (name, options) {
  831. if (!name) {
  832. throw new Error("null name");
  833. }
  834. options = options || {
  835. };
  836. var url = "Persons/" + name + "/Images/" + options.type;
  837. if (options.index != null) {
  838. url += "/" + options.index;
  839. }
  840. // Don't put these on the query string
  841. delete options.type;
  842. delete options.index;
  843. return self.getUrl(url, options);
  844. };
  845. /**
  846. * Constructs a url for a year image
  847. * @param {String} year
  848. * @param {Object} options
  849. * Options supports the following properties:
  850. * width - download the image at a fixed width
  851. * height - download the image at a fixed height
  852. * maxWidth - download the image at a maxWidth
  853. * maxHeight - download the image at a maxHeight
  854. * quality - A scale of 0-100. This should almost always be omitted as the default will suffice.
  855. * For best results do not specify both width and height together, as aspect ratio might be altered.
  856. */
  857. self.getYearImageUrl = function (year, options) {
  858. if (!year) {
  859. throw new Error("null year");
  860. }
  861. options = options || {
  862. };
  863. var url = "Years/" + year + "/Images/" + options.type;
  864. if (options.index != null) {
  865. url += "/" + options.index;
  866. }
  867. // Don't put these on the query string
  868. delete options.type;
  869. delete options.index;
  870. return self.getUrl(url, options);
  871. };
  872. /**
  873. * Constructs a url for a genre image
  874. * @param {String} name
  875. * @param {Object} options
  876. * Options supports the following properties:
  877. * width - download the image at a fixed width
  878. * height - download the image at a fixed height
  879. * maxWidth - download the image at a maxWidth
  880. * maxHeight - download the image at a maxHeight
  881. * quality - A scale of 0-100. This should almost always be omitted as the default will suffice.
  882. * For best results do not specify both width and height together, as aspect ratio might be altered.
  883. */
  884. self.getGenreImageUrl = function (name, options) {
  885. if (!name) {
  886. throw new Error("null name");
  887. }
  888. options = options || {
  889. };
  890. var url = "Genres/" + name + "/Images/" + options.type;
  891. if (options.index != null) {
  892. url += "/" + options.index;
  893. }
  894. // Don't put these on the query string
  895. delete options.type;
  896. delete options.index;
  897. return self.getUrl(url, options);
  898. };
  899. /**
  900. * Constructs a url for a genre image
  901. * @param {String} name
  902. * @param {Object} options
  903. * Options supports the following properties:
  904. * width - download the image at a fixed width
  905. * height - download the image at a fixed height
  906. * maxWidth - download the image at a maxWidth
  907. * maxHeight - download the image at a maxHeight
  908. * quality - A scale of 0-100. This should almost always be omitted as the default will suffice.
  909. * For best results do not specify both width and height together, as aspect ratio might be altered.
  910. */
  911. self.getStudioImageUrl = function (name, options) {
  912. if (!name) {
  913. throw new Error("null name");
  914. }
  915. options = options || {
  916. };
  917. var url = "Studios/" + name + "/Images/" + options.type;
  918. if (options.index != null) {
  919. url += "/" + options.index;
  920. }
  921. // Don't put these on the query string
  922. delete options.type;
  923. delete options.index;
  924. return self.getUrl(url, options);
  925. };
  926. /**
  927. * Constructs a url for an item image
  928. * @param {String} itemId
  929. * @param {Object} options
  930. * Options supports the following properties:
  931. * type - Primary, logo, backdrop, etc. See the server-side enum ImageType
  932. * index - When downloading a backdrop, use this to specify which one (omitting is equivalent to zero)
  933. * width - download the image at a fixed width
  934. * height - download the image at a fixed height
  935. * maxWidth - download the image at a maxWidth
  936. * maxHeight - download the image at a maxHeight
  937. * quality - A scale of 0-100. This should almost always be omitted as the default will suffice.
  938. * For best results do not specify both width and height together, as aspect ratio might be altered.
  939. */
  940. self.getImageUrl = function (itemId, options) {
  941. if (!itemId) {
  942. throw new Error("itemId cannot be empty");
  943. }
  944. options = options || {
  945. };
  946. var url = "Items/" + itemId + "/Images/" + options.type;
  947. if (options.index != null) {
  948. url += "/" + options.index;
  949. }
  950. // Don't put these on the query string
  951. delete options.type;
  952. delete options.index;
  953. return self.getUrl(url, options);
  954. };
  955. /**
  956. * Constructs a url for an item logo image
  957. * If the item doesn't have a logo, it will inherit a logo from a parent
  958. * @param {Object} item A BaseItem
  959. * @param {Object} options
  960. * Options supports the following properties:
  961. * width - download the image at a fixed width
  962. * height - download the image at a fixed height
  963. * maxWidth - download the image at a maxWidth
  964. * maxHeight - download the image at a maxHeight
  965. * quality - A scale of 0-100. This should almost always be omitted as the default will suffice.
  966. * For best results do not specify both width and height together, as aspect ratio might be altered.
  967. */
  968. self.getLogoImageUrl = function (item, options) {
  969. if (!item) {
  970. throw new Error("null item");
  971. }
  972. options = options || {
  973. };
  974. options.imageType = "logo";
  975. var logoItemId = item.HasLogo ? item.Id : item.ParentLogoItemId;
  976. return logoItemId ? self.getImageUrl(logoItemId, options) : null;
  977. };
  978. /**
  979. * Constructs an array of backdrop image url's for an item
  980. * If the item doesn't have any backdrops, it will inherit them from a parent
  981. * @param {Object} item A BaseItem
  982. * @param {Object} options
  983. * Options supports the following properties:
  984. * width - download the image at a fixed width
  985. * height - download the image at a fixed height
  986. * maxWidth - download the image at a maxWidth
  987. * maxHeight - download the image at a maxHeight
  988. * quality - A scale of 0-100. This should almost always be omitted as the default will suffice.
  989. * For best results do not specify both width and height together, as aspect ratio might be altered.
  990. */
  991. self.getBackdropImageUrl = function (item, options) {
  992. if (!item) {
  993. throw new Error("null item");
  994. }
  995. options = options || {
  996. };
  997. options.imageType = "backdrop";
  998. var backdropItemId;
  999. var backdropCount;
  1000. if (!item.BackdropCount) {
  1001. backdropItemId = item.ParentBackdropItemId;
  1002. backdropCount = item.ParentBackdropCount || 0;
  1003. } else {
  1004. backdropItemId = item.Id;
  1005. backdropCount = item.BackdropCount;
  1006. }
  1007. if (!backdropItemId) {
  1008. return [];
  1009. }
  1010. var files = [];
  1011. for (var i = 0; i < backdropCount; i++) {
  1012. options.imageIndex = i;
  1013. files[i] = self.getImageUrl(backdropItemId, options);
  1014. }
  1015. return files;
  1016. };
  1017. /**
  1018. * Authenticates a user
  1019. * @param {String} userId
  1020. * @param {String} password
  1021. */
  1022. self.authenticateUser = function (userId, password) {
  1023. if (!userId) {
  1024. throw new Error("null userId");
  1025. }
  1026. var url = self.getUrl("Users/" + userId + "/authenticate");
  1027. var postData = {
  1028. password: MediaBrowser.SHA1(password || "")
  1029. };
  1030. return self.ajax({
  1031. type: "POST",
  1032. url: url,
  1033. data: JSON.stringify(postData),
  1034. dataType: "json",
  1035. contentType: "application/json"
  1036. });
  1037. };
  1038. /**
  1039. * Updates a user's password
  1040. * @param {String} userId
  1041. * @param {String} currentPassword
  1042. * @param {String} newPassword
  1043. */
  1044. self.updateUserPassword = function (userId, currentPassword, newPassword) {
  1045. if (!userId) {
  1046. throw new Error("null userId");
  1047. }
  1048. var url = self.getUrl("Users/" + userId + "/Password");
  1049. var postData = {
  1050. };
  1051. postData.currentPassword = MediaBrowser.SHA1(currentPassword);
  1052. if (newPassword) {
  1053. postData.newPassword = newPassword;
  1054. }
  1055. return self.ajax({
  1056. type: "POST",
  1057. url: url,
  1058. data: postData
  1059. });
  1060. };
  1061. /**
  1062. * Resets a user's password
  1063. * @param {String} userId
  1064. */
  1065. self.resetUserPassword = function (userId) {
  1066. if (!userId) {
  1067. throw new Error("null userId");
  1068. }
  1069. var url = self.getUrl("Users/" + userId + "/Password");
  1070. var postData = {
  1071. };
  1072. postData.resetPassword = true;
  1073. return self.ajax({
  1074. type: "POST",
  1075. url: url,
  1076. data: postData
  1077. });
  1078. };
  1079. /**
  1080. * Updates the server's configuration
  1081. * @param {Object} configuration
  1082. */
  1083. self.updateServerConfiguration = function (configuration) {
  1084. if (!configuration) {
  1085. throw new Error("null configuration");
  1086. }
  1087. var url = self.getUrl("System/Configuration");
  1088. return self.ajax({
  1089. type: "POST",
  1090. url: url,
  1091. data: JSON.stringify(configuration),
  1092. dataType: "json",
  1093. contentType: "application/json"
  1094. });
  1095. };
  1096. /**
  1097. * Updates plugin security info
  1098. */
  1099. self.updatePluginSecurityInfo = function (info) {
  1100. var url = self.getUrl("Plugins/SecurityInfo");
  1101. return self.ajax({
  1102. type: "POST",
  1103. url: url,
  1104. data: JSON.stringify(info),
  1105. dataType: "json",
  1106. contentType: "application/json"
  1107. });
  1108. };
  1109. /**
  1110. * Creates a user
  1111. * @param {Object} user
  1112. */
  1113. self.createUser = function (user) {
  1114. if (!user) {
  1115. throw new Error("null user");
  1116. }
  1117. var url = self.getUrl("Users");
  1118. return self.ajax({
  1119. type: "POST",
  1120. url: url,
  1121. data: JSON.stringify(user),
  1122. dataType: "json",
  1123. contentType: "application/json"
  1124. });
  1125. };
  1126. /**
  1127. * Updates a user
  1128. * @param {Object} user
  1129. */
  1130. self.updateUser = function (user) {
  1131. if (!user) {
  1132. throw new Error("null user");
  1133. }
  1134. var url = self.getUrl("Users/" + user.Id);
  1135. return self.ajax({
  1136. type: "POST",
  1137. url: url,
  1138. data: JSON.stringify(user),
  1139. dataType: "json",
  1140. contentType: "application/json"
  1141. });
  1142. };
  1143. /**
  1144. * Updates the Triggers for a ScheduledTask
  1145. * @param {String} id
  1146. * @param {Object} triggers
  1147. */
  1148. self.updateScheduledTaskTriggers = function (id, triggers) {
  1149. if (!id) {
  1150. throw new Error("null id");
  1151. }
  1152. if (!triggers) {
  1153. throw new Error("null triggers");
  1154. }
  1155. var url = self.getUrl("ScheduledTasks/" + id + "/Triggers");
  1156. return self.ajax({
  1157. type: "POST",
  1158. url: url,
  1159. data: JSON.stringify(triggers),
  1160. dataType: "json",
  1161. contentType: "application/json"
  1162. });
  1163. };
  1164. /**
  1165. * Updates a plugin's configuration
  1166. * @param {String} Id
  1167. * @param {Object} configuration
  1168. */
  1169. self.updatePluginConfiguration = function (id, configuration) {
  1170. if (!id) {
  1171. throw new Error("null Id");
  1172. }
  1173. if (!configuration) {
  1174. throw new Error("null configuration");
  1175. }
  1176. var url = self.getUrl("Plugins/" + id + "/Configuration");
  1177. return self.ajax({
  1178. type: "POST",
  1179. url: url,
  1180. data: JSON.stringify(configuration),
  1181. dataType: "json",
  1182. contentType: "application/json"
  1183. });
  1184. };
  1185. /**
  1186. * Gets items based on a query, typicall for children of a folder
  1187. * @param {String} userId
  1188. * @param {Object} options
  1189. * Options accepts the following properties:
  1190. * itemId - Localize the search to a specific folder (root if omitted)
  1191. * startIndex - Use for paging
  1192. * limit - Use to limit results to a certain number of items
  1193. * filter - Specify one or more ItemFilters, comma delimeted (see server-side enum)
  1194. * sortBy - Specify an ItemSortBy (comma-delimeted list see server-side enum)
  1195. * sortOrder - ascending/descending
  1196. * fields - additional fields to include aside from basic info. This is a comma delimited list. See server-side enum ItemFields.
  1197. * index - the name of the dynamic, localized index function
  1198. * dynamicSortBy - the name of the dynamic localized sort function
  1199. * recursive - Whether or not the query should be recursive
  1200. * searchTerm - search term to use as a filter
  1201. */
  1202. self.getItems = function (userId, options) {
  1203. if (!userId) {
  1204. throw new Error("null userId");
  1205. }
  1206. var url = self.getUrl("Users/" + userId + "/Items", options);
  1207. return self.ajax({
  1208. type: "GET",
  1209. url: url,
  1210. dataType: "json"
  1211. });
  1212. };
  1213. /**
  1214. * Marks an item as played or unplayed
  1215. * This should not be used to update playstate following playback.
  1216. * There are separate playstate check-in methods for that. This should be used for a
  1217. * separate option to reset playstate.
  1218. * @param {String} userId
  1219. * @param {String} itemId
  1220. * @param {Boolean} wasPlayed
  1221. */
  1222. self.updatePlayedStatus = function (userId, itemId, wasPlayed) {
  1223. if (!userId) {
  1224. throw new Error("null userId");
  1225. }
  1226. if (!itemId) {
  1227. throw new Error("null itemId");
  1228. }
  1229. var url = "Users/" + userId + "/PlayedItems/" + itemId;
  1230. var method = wasPlayed ? "POST" : "DELETE";
  1231. return self.ajax({
  1232. type: method,
  1233. url: url,
  1234. dataType: "json"
  1235. });
  1236. };
  1237. /**
  1238. * Updates a user's favorite status for an item and returns the updated UserItemData object.
  1239. * @param {String} userId
  1240. * @param {String} itemId
  1241. * @param {Boolean} isFavorite
  1242. */
  1243. self.updateFavoriteStatus = function (userId, itemId, isFavorite) {
  1244. if (!userId) {
  1245. throw new Error("null userId");
  1246. }
  1247. if (!itemId) {
  1248. throw new Error("null itemId");
  1249. }
  1250. var url = "Users/" + userId + "/FavoriteItems/" + itemId;
  1251. var method = isFavorite ? "POST" : "DELETE";
  1252. return self.ajax({
  1253. type: method,
  1254. url: url,
  1255. dataType: "json"
  1256. });
  1257. };
  1258. /**
  1259. * Updates a user's personal rating for an item
  1260. * @param {String} userId
  1261. * @param {String} itemId
  1262. * @param {Boolean} likes
  1263. */
  1264. self.updateUserItemRating = function (userId, itemId, likes) {
  1265. if (!userId) {
  1266. throw new Error("null userId");
  1267. }
  1268. if (!itemId) {
  1269. throw new Error("null itemId");
  1270. }
  1271. var url = self.getUrl("Users/" + userId + "/Items/" + itemId + "/Rating", {
  1272. likes: likes
  1273. });
  1274. return self.ajax({
  1275. type: "POST",
  1276. url: url
  1277. });
  1278. };
  1279. /**
  1280. * Clears a user's personal rating for an item
  1281. * @param {String} userId
  1282. * @param {String} itemId
  1283. */
  1284. self.clearUserItemRating = function (userId, itemId) {
  1285. if (!userId) {
  1286. throw new Error("null userId");
  1287. }
  1288. if (!itemId) {
  1289. throw new Error("null itemId");
  1290. }
  1291. var url = self.getUrl("Users/" + userId + "/Items/" + itemId + "/Rating");
  1292. return self.ajax({
  1293. type: "DELETE",
  1294. url: url,
  1295. dataType: "json"
  1296. });
  1297. };
  1298. /**
  1299. * Reports the user has started playing something
  1300. * @param {String} userId
  1301. * @param {String} itemId
  1302. */
  1303. self.reportPlaybackStart = function (userId, itemId) {
  1304. if (!userId) {
  1305. throw new Error("null userId");
  1306. }
  1307. if (!itemId) {
  1308. throw new Error("null itemId");
  1309. }
  1310. var url = self.getUrl("Users/" + userId + "/PlayingItems/" + itemId);
  1311. return self.ajax({
  1312. type: "POST",
  1313. url: url,
  1314. dataType: "json"
  1315. });
  1316. };
  1317. /**
  1318. * Reports progress viewing an item
  1319. * @param {String} userId
  1320. * @param {String} itemId
  1321. */
  1322. self.reportPlaybackProgress = function (userId, itemId, positionTicks) {
  1323. if (!userId) {
  1324. throw new Error("null userId");
  1325. }
  1326. if (!itemId) {
  1327. throw new Error("null itemId");
  1328. }
  1329. var params = {
  1330. };
  1331. if (positionTicks) {
  1332. params.positionTicks = positionTicks;
  1333. }
  1334. var url = self.getUrl("Users/" + userId + "/PlayingItems/" + itemId + "/Progress", params);
  1335. return self.ajax({
  1336. type: "POST",
  1337. url: url,
  1338. dataType: "json"
  1339. });
  1340. };
  1341. /**
  1342. * Reports a user has stopped playing an item
  1343. * @param {String} userId
  1344. * @param {String} itemId
  1345. */
  1346. self.reportPlaybackStopped = function (userId, itemId, positionTicks) {
  1347. if (!userId) {
  1348. throw new Error("null userId");
  1349. }
  1350. if (!itemId) {
  1351. throw new Error("null itemId");
  1352. }
  1353. var params = {
  1354. };
  1355. if (positionTicks) {
  1356. params.positionTicks = positionTicks;
  1357. }
  1358. var url = self.getUrl("Users/" + userId + "/PlayingItems/" + itemId, params);
  1359. return self.ajax({
  1360. type: "DELETE",
  1361. url: url,
  1362. dataType: "json"
  1363. });
  1364. };
  1365. }
  1366. }(jQuery, navigator, JSON, window.WebSocket, setTimeout);
  1367. /**
  1368. * Provides a friendly way to create an api client instance using information from the browser's current url
  1369. */
  1370. MediaBrowser.ApiClient.create = function (clientName) {
  1371. var loc = window.location;
  1372. return new MediaBrowser.ApiClient(loc.protocol, loc.hostname, loc.port, clientName);
  1373. };
  1374. /**
  1375. *
  1376. * Secure Hash Algorithm (SHA1)
  1377. * http://www.webtoolkit.info/
  1378. *
  1379. **/
  1380. MediaBrowser.SHA1 = function (msg) {
  1381. function rotate_left(n, s) {
  1382. var t4 = (n << s) | (n >>> (32 - s));
  1383. return t4;
  1384. }
  1385. function lsb_hex(val) {
  1386. var str = "";
  1387. var i;
  1388. var vh;
  1389. var vl;
  1390. for (i = 0; i <= 6; i += 2) {
  1391. vh = (val >>> (i * 4 + 4)) & 0x0f;
  1392. vl = (val >>> (i * 4)) & 0x0f;
  1393. str += vh.toString(16) + vl.toString(16);
  1394. }
  1395. return str;
  1396. }
  1397. function cvt_hex(val) {
  1398. var str = "";
  1399. var i;
  1400. var v;
  1401. for (i = 7; i >= 0; i--) {
  1402. v = (val >>> (i * 4)) & 0x0f;
  1403. str += v.toString(16);
  1404. }
  1405. return str;
  1406. }
  1407. function Utf8Encode(string) {
  1408. string = string.replace(/\r\n/g, "\n");
  1409. var utftext = "";
  1410. for (var n = 0; n < string.length; n++) {
  1411. var c = string.charCodeAt(n);
  1412. if (c < 128) {
  1413. utftext += String.fromCharCode(c);
  1414. }
  1415. else if ((c > 127) && (c < 2048)) {
  1416. utftext += String.fromCharCode((c >> 6) | 192);
  1417. utftext += String.fromCharCode((c & 63) | 128);
  1418. }
  1419. else {
  1420. utftext += String.fromCharCode((c >> 12) | 224);
  1421. utftext += String.fromCharCode(((c >> 6) & 63) | 128);
  1422. utftext += String.fromCharCode((c & 63) | 128);
  1423. }
  1424. }
  1425. return utftext;
  1426. }
  1427. var blockstart;
  1428. var i, j;
  1429. var W = new Array(80);
  1430. var H0 = 0x67452301;
  1431. var H1 = 0xEFCDAB89;
  1432. var H2 = 0x98BADCFE;
  1433. var H3 = 0x10325476;
  1434. var H4 = 0xC3D2E1F0;
  1435. var A, B, C, D, E;
  1436. var temp;
  1437. msg = Utf8Encode(msg);
  1438. var msg_len = msg.length;
  1439. var word_array = new Array();
  1440. for (i = 0; i < msg_len - 3; i += 4) {
  1441. j = msg.charCodeAt(i) << 24 | msg.charCodeAt(i + 1) << 16 |
  1442. msg.charCodeAt(i + 2) << 8 | msg.charCodeAt(i + 3);
  1443. word_array.push(j);
  1444. }
  1445. switch (msg_len % 4) {
  1446. case 0:
  1447. i = 0x080000000;
  1448. break;
  1449. case 1:
  1450. i = msg.charCodeAt(msg_len - 1) << 24 | 0x0800000;
  1451. break;
  1452. case 2:
  1453. i = msg.charCodeAt(msg_len - 2) << 24 | msg.charCodeAt(msg_len - 1) << 16 | 0x08000;
  1454. break;
  1455. case 3:
  1456. i = msg.charCodeAt(msg_len - 3) << 24 | msg.charCodeAt(msg_len - 2) << 16 | msg.charCodeAt(msg_len - 1) << 8 | 0x80;
  1457. break;
  1458. }
  1459. word_array.push(i);
  1460. while ((word_array.length % 16) != 14) word_array.push(0);
  1461. word_array.push(msg_len >>> 29);
  1462. word_array.push((msg_len << 3) & 0x0ffffffff);
  1463. for (blockstart = 0; blockstart < word_array.length; blockstart += 16) {
  1464. for (i = 0; i < 16; i++) W[i] = word_array[blockstart + i];
  1465. for (i = 16; i <= 79; i++) W[i] = rotate_left(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1);
  1466. A = H0;
  1467. B = H1;
  1468. C = H2;
  1469. D = H3;
  1470. E = H4;
  1471. for (i = 0; i <= 19; i++) {
  1472. temp = (rotate_left(A, 5) + ((B & C) | (~B & D)) + E + W[i] + 0x5A827999) & 0x0ffffffff;
  1473. E = D;
  1474. D = C;
  1475. C = rotate_left(B, 30);
  1476. B = A;
  1477. A = temp;
  1478. }
  1479. for (i = 20; i <= 39; i++) {
  1480. temp = (rotate_left(A, 5) + (B ^ C ^ D) + E + W[i] + 0x6ED9EBA1) & 0x0ffffffff;
  1481. E = D;
  1482. D = C;
  1483. C = rotate_left(B, 30);
  1484. B = A;
  1485. A = temp;
  1486. }
  1487. for (i = 40; i <= 59; i++) {
  1488. temp = (rotate_left(A, 5) + ((B & C) | (B & D) | (C & D)) + E + W[i] + 0x8F1BBCDC) & 0x0ffffffff;
  1489. E = D;
  1490. D = C;
  1491. C = rotate_left(B, 30);
  1492. B = A;
  1493. A = temp;
  1494. }
  1495. for (i = 60; i <= 79; i++) {
  1496. temp = (rotate_left(A, 5) + (B ^ C ^ D) + E + W[i] + 0xCA62C1D6) & 0x0ffffffff;
  1497. E = D;
  1498. D = C;
  1499. C = rotate_left(B, 30);
  1500. B = A;
  1501. A = temp;
  1502. }
  1503. H0 = (H0 + A) & 0x0ffffffff;
  1504. H1 = (H1 + B) & 0x0ffffffff;
  1505. H2 = (H2 + C) & 0x0ffffffff;
  1506. H3 = (H3 + D) & 0x0ffffffff;
  1507. H4 = (H4 + E) & 0x0ffffffff;
  1508. }
  1509. var temp = cvt_hex(H0) + cvt_hex(H1) + cvt_hex(H2) + cvt_hex(H3) + cvt_hex(H4);
  1510. return temp.toLowerCase();
  1511. };