verify.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. const fs = require("fs");
  2. const axios = require("axios");
  3. const oldFilename = `oldChannels.json`;
  4. const newFilename = `newVideos.json`;
  5. const resultsFilename = `migration_result.json`;
  6. const { channels, videos } = require("./ids.js");
  7. console.log(
  8. `Loaded IDs of ${videos.length} transferred videos in ${channels.length} channels.`
  9. );
  10. //const { channels } = require("./ru.js");
  11. // channels.map((c) => c.id).reduce((id=> axios.head(`${}`))
  12. const oldChannels = `query { channels (limit: 10000) { id createdAt updatedAt createdInBlock
  13. title category { name } ownerMember {id handle } isCensored isPublic
  14. coverPhotoAvailability coverPhotoDataObject { joystreamContentId size }
  15. avatarPhotoAvailability avatarPhotoDataObject { joystreamContentId size }
  16. videos { id title mediaDataObject {size} mediaAvailability thumbnailPhotoAvailability }
  17. }}`;
  18. const queryVideos = `query { videos (limit:10000) { id channelId language{iso} media { id } }}`;
  19. const queryVideo = (id) => `query { videos(where: {id_eq: "${id}"}) {
  20. id channelId language{iso} media { id } }}`;
  21. //curl 'https://ipfs.joystreamstats.live/graphql' -H 'Accept-Encoding: gzip, deflate, br' -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'Connection: keep-alive' -H 'DNT: 1' -H 'Origin: https://ipfs.joystreamstats.live' --data-binary '{"query":"query { videos { id channelId language{iso} media { id } }}"}' --compressed
  22. const getOldChannels = () =>
  23. axios
  24. .post(`https://hydra-sumer.joystream.org/graphql`, { query: oldChannels })
  25. .then(({ data }) => {
  26. fs.writeFileSync(oldFilename, JSON.stringify(data.data.channels));
  27. return data.data.channels;
  28. })
  29. .catch(({ message, response }) => {
  30. console.log(response.status, message, response.data);
  31. return [];
  32. });
  33. const printResults = (results) => {
  34. const available = results.filter((v) => v.status === `available`);
  35. console.log(`${available.length} of ${results.length} assets are available.`);
  36. const notok = results.filter((v) => v.status !== `available`);
  37. if (!notok.length) return;
  38. // print table
  39. const header = `\n### Created Videos without media file\n\n${notok.length} have no content.\n\n| Channel | Video | Asset | Status |\n|---|---|---|---|\n`;
  40. const row = ({ id, channelId, media, status }) =>
  41. `| ${channelId} | ${id} | ${media?.id || ``} | ${status || ``} |`;
  42. const sorted = notok.sort((a, b) => a.channelId - b.channelId);
  43. console.log(header + sorted.map((video) => row(video)).join(`\n`));
  44. };
  45. const testVideos = async (list, oldResults) => {
  46. if (!list?.length) return console.log(`empty result from QN`);
  47. console.log(`Testing availability of ${list.length} videos (~5..15min)`);
  48. let results = oldResults || [];
  49. const timer = setInterval(
  50. () => console.log(`Tested ${results.length} videos.`),
  51. 5000
  52. );
  53. for (const video of list) {
  54. const { id, channelId, language, media } = video;
  55. if (!videos.find((map) => +map[1] === +id)) continue; // not migrated
  56. if (!media) {
  57. console.log(`Skipping video ${id}: no media info.`);
  58. results.push({ ...video, status: `no media` });
  59. continue;
  60. }
  61. const status = await axios
  62. .head(`https://storage-1.joystream.org/argus/api/v1/assets/${media.id}`)
  63. .then(({ status, statusText }) =>
  64. status === 200 ? `available` : `${status} ${statusText}`
  65. )
  66. .catch((error) => error.message);
  67. if (status !== "available") console.log(`Not available:`, video);
  68. results.push({ ...video, status });
  69. }
  70. fs.writeFileSync(resultsFilename, JSON.stringify(results));
  71. console.log(`Wrote ${resultsFilename}.`);
  72. printResults(results);
  73. clearInterval(timer);
  74. };
  75. const countSize = (ids, channels) => {
  76. let acceptedVideos = 0;
  77. let channelsSize = 0;
  78. let sizes = [];
  79. let notacceptedbuttransferred = [];
  80. channels
  81. .filter((c) => ids.find((id) => id[0] === +c.id))
  82. .map((channel) => {
  83. if (channel.isCensored) console.log(`channel ${cid} was censored!`);
  84. if (channel.coverPhotoDataObject)
  85. channelsSize += channel.coverPhotoDataObject.size;
  86. if (channel.avatarPhotoDataObject)
  87. channelsSize += channel.avatarPhotoDataObject.size;
  88. channel.videos.forEach((v) => {
  89. if (v.mediaAvailability === "ACCEPTED")
  90. sizes.push(v.mediaDataObject.size);
  91. else notacceptedbuttransferred.push(v);
  92. });
  93. });
  94. const bytes = sizes.reduce((a, b) => a + b, 0);
  95. console.log(
  96. `${sizes.length} videos were transferred ${bytes} bytes + ${channelsSize} avatars + covers.`
  97. );
  98. if (notacceptedbuttransferred) {
  99. const lines = notacceptedbuttransferred.map(
  100. (v) =>
  101. `| ${v.id} | ${v.title} | ${v.mediaDataObject.size} | ${v.mediaAvailability} | ${v.thumbnailPhotoAvailability} |`
  102. );
  103. console.log(
  104. `\n### Migrated ${lines.length} videos with empty source\n\n|ID|Title|Size|Upload|Thumbnail|\n|---|---|---|---|---|\n`,
  105. lines.join(`\n`)
  106. );
  107. }
  108. return bytes + channelsSize;
  109. };
  110. // load old channels from disk or old QN
  111. fs.stat(oldFilename, async (err, stat) => {
  112. const oldChannels = !err
  113. ? JSON.parse(fs.readFileSync(oldFilename, "utf-8"))
  114. : await getOldChannels();
  115. console.log(`Loaded info of ${oldChannels.length} old channels.`);
  116. const size = countSize(channels, oldChannels);
  117. // find censored
  118. const censored = oldChannels.filter((c) => c.isCensored);
  119. if (!censored.length) return;
  120. console.log(
  121. `\n### Censored source channels\n\nFound ${censored.length} censored channels in migration set:\n`,
  122. "```\n" + censored.map((j) => JSON.stringify(j)).join("\n") + "\n```"
  123. );
  124. });
  125. // load new videos from disk or new QN
  126. fs.stat(newFilename, async (err, stat) => {
  127. const newVideos = !err
  128. ? JSON.parse(fs.readFileSync(newFilename, "utf-8"))
  129. : await axios
  130. .post(`https://ipfs.joystreamstats.live/graphql`, {
  131. query: queryVideos,
  132. })
  133. .then(({ data }) => {
  134. fs.writeFileSync(newFilename, JSON.stringify(data.data.videos));
  135. return data.data.videos;
  136. })
  137. .catch((error) => {
  138. console.log(error.message, error);
  139. return [];
  140. });
  141. // find migrated of all new videos
  142. const migrated = newVideos.filter((v) =>
  143. videos.find((ids) => ids[1] === +v.id)
  144. );
  145. if (!migrated.length)
  146. return console.log(
  147. `Something went wrong. No migrated videos found. Contact your administrator.`
  148. );
  149. console.log(`Loaded info of ${migrated.length} migrated videos.`);
  150. fs.stat(resultsFilename, async (err, stat) => {
  151. if (err) return testVideos(migrated);
  152. console.log(`Loading old results.`);
  153. const results = JSON.parse(fs.readFileSync(resultsFilename, "utf-8"));
  154. const nottested = videos.filter(
  155. (i) => !results.find((r) => +r.id === i[1])
  156. );
  157. console.log(nottested.length, `not tested before.`);
  158. if (nottested.length) return testVideos(nottested, results);
  159. console.log(`Nothing to do. all migrated Videos were tested.`);
  160. printResults(results);
  161. });
  162. });