backup.html 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <link rel="icon" href="favicon.ico" type="image/x-icon">
  5. <title>Backup/Restore Configuration</title>
  6. <meta charset="utf-8">
  7. <style>
  8. h1 {font-size: 2em;}
  9. h2 {font-size: 1.5em;}
  10. h3 {font-size: 1.2em;}
  11. p {font-size: 1em;}
  12. input[type=number] {
  13. width: 138px;
  14. padding: 10px 5px;
  15. display: inline-block;
  16. border: 1px solid #ccc;
  17. font-size: 16px;
  18. }
  19. .button {
  20. padding: 10px 20px;
  21. width: 211px;
  22. font-size: 16px;
  23. }
  24. </style>
  25. </head>
  26. <body style="font-family: arial; padding: 0px 10px;">
  27. <h2>Backup Configuration</h2>
  28. <p>With the following action the <a href="/fileserver/config/" target="_self">config</a> folder on the SD-card gets zipped and provided as a download.</p>
  29. <table border="0">
  30. </tr>
  31. <td>
  32. <button class="button" id="doBackup" type="button" onclick="doBackup()">Create Config backup</button>
  33. </td>
  34. <td>
  35. <p id=progress></p>
  36. </td>
  37. </tr>
  38. </table>
  39. <hr>
  40. <h2>Restore Configuration</h2>
  41. <p>Use the <a href="/fileserver/config/" target="_self">File Server</a> to upload individual files.</p>
  42. </body>
  43. <script src="jszip.min.js"></script>
  44. <script src="FileSaver.min.js"></script>
  45. <script>
  46. function doBackup() {
  47. document.getElementById("progress").innerHTML = "Creating backup...";
  48. // Get hostname
  49. try {
  50. var xhttp = new XMLHttpRequest();
  51. xhttp.open("GET", "/version?type=Hostname", false);
  52. xhttp.send();
  53. hostname = xhttp.responseText;
  54. }
  55. catch(err) {
  56. alert("Failed to fetch hostname: " + err.message);
  57. return;
  58. }
  59. // get date/time
  60. var dateTime = new Date().toJSON().slice(0,10) + "_" + new Date().toJSON().slice(11,19).replaceAll(":", "-");
  61. zipFilename = hostname + "_" + dateTime + ".zip";
  62. console.log(zipFilename);
  63. // Get files list
  64. try {
  65. var xhttp = new XMLHttpRequest();
  66. xhttp.open("GET", "/fileserver/config/", false);
  67. xhttp.send();
  68. var parser = new DOMParser();
  69. var content = parser.parseFromString(xhttp.responseText, 'text/html'); }
  70. catch(err) {
  71. alert("Failed to fetch files list: " + err.message);
  72. return;
  73. }
  74. const list = content.querySelectorAll("a");
  75. var urls = [];
  76. for (a of list) {
  77. url = a.getAttribute("href");
  78. urls.push(url);
  79. }
  80. // Pack as zip and download
  81. try {
  82. saveZip(zipFilename, urls);
  83. }
  84. catch(err) {
  85. alert("Failed to zip files: " + err.message);
  86. return;
  87. }
  88. }
  89. const saveZip = (filename, urls) => {
  90. if(!urls) return;
  91. const zip = new JSZip();
  92. const folder = zip.folder("");
  93. var i = 0;
  94. urls.forEach((url) => {
  95. const blobPromise = fetch(url).then((r) => {
  96. if (r.status === 200) return r.blob();
  97. return Promise.reject(new Error(r.statusText));
  98. });
  99. const name = url.substring(url.lastIndexOf("/") + 1);
  100. folder.file(name, blobPromise);
  101. });
  102. zip.generateAsync({ type: "blob" },
  103. function updateCallback(metadata) {
  104. var msg = "Progress: " + metadata.percent.toFixed(0) + "%";
  105. if(metadata.currentFile) {
  106. msg += ", " + metadata.currentFile;
  107. }
  108. console.log(msg);
  109. document.getElementById("progress").innerHTML = msg;
  110. }
  111. ).then((blob) => saveAs(blob, filename));
  112. };
  113. </script>
  114. </html>