Browse Source

33.CC-2 display setCategoryFeaturedVideos requests

Joystream Stats 3 years ago
parent
commit
66704c84d5

+ 9 - 5
working-groups/curator-group/featured/README.md

@@ -1,8 +1,12 @@
 # [32.CC-2 - Update Featured Categories](https://blog.joystream.org/sumer-kpis/#32.CC-2)
 
-Re-generate schedule: `node generateSchedule.js`
+```
+yarn
+yarn run categories COMMAND
+```
 
-Update `videos.json` after changing files:
-- Enter directory `Discover Category Videos`
-- Generate file list: `find > list`
-- `node updateVideos.js`
+Commands
+- `get`: show current category videos // TODO FIX
+- `set`: display mutation requests
+- `update`: updates videos.json from `list` (generate with `find DirectoryWithCategoryVideosCuts > list`
+- `schedule`: regenerates schedule

+ 180 - 0
working-groups/curator-group/featured/categories.ts

@@ -0,0 +1,180 @@
+import { Video, OrionVideo, Category, Schedule } from "./types";
+import fs from "fs";
+import axios from "axios";
+import moment from "moment";
+import dotenv from "dotenv";
+dotenv.config();
+const orionHeader = process.env.orionHeader;
+const orionUrl = `https://orion.joystream.org/graphql`;
+const videosFile = "./videos.json";
+const scheduleFile = "./schedule.json";
+
+if (!orionHeader) {
+  console.log(`Please set orionHeader in .env`);
+  process.exit(1);
+}
+
+const getDay = (daysFromNow: number = 0) =>
+  moment().add(daysFromNow, "days").format("YYYY-MM-DD");
+
+export const getOrionVideo = ({ videoId }: Video): OrionVideo => {
+  return {
+    videoId,
+    videoCutUrl: `https://eu-central-1.linodeobjects.com/atlas-featured-content/category-featured-videos/1/video-cut-${videoId}.mp4`,
+  };
+};
+
+const loadSchedule = () => require(scheduleFile);
+
+const loadVideos = (): { videos: Video[]; categories: number[] } => {
+  // load videos and extract category IDs
+  const categories: number[] = [];
+  const videos: Video[] = require(videosFile);
+  videos.forEach(
+    ({ categoryId }) =>
+      categories.includes(categoryId) || categories.push(categoryId)
+  );
+  return { videos, categories };
+};
+
+const selectVideos = (videos: Video[], count: number): OrionVideo[] => {
+  let selected: OrionVideo[] = [];
+  for (let n = 0; n < count; ++n) {
+    // remove selected videos
+    const available: Video[] = videos.filter(
+      ({ videoId }) => !selected.find((v) => v.videoId === videoId)
+    );
+    // select random video
+    const id = Math.floor(Math.random() * available.length);
+    if (available.length && available[id])
+      selected.push(getOrionVideo(available[id]));
+    else break;
+  }
+  return selected;
+};
+
+const generateVideoList = (file: string) => {
+  console.log(`Indexing video files ..`);
+  const videos = fs
+    .readFileSync(`./list`, `utf-8`)
+    .split(`\n`)
+    .reduce((list: Video[], path: string): Video[] => {
+      const match = path.match(/\.\/([^\/]+) (\d+)\/(\d+)-(\d+)\.mp4/);
+      if (match) {
+        const category = match[1];
+        const count = Number(match[2]);
+        const categoryId = Number(match[3]);
+        const videoId = Number(match[4]);
+        const video: Video = { category, count, categoryId, videoId };
+        return list.concat(video);
+      } else return list;
+    }, []);
+  fs.writeFileSync(file, JSON.stringify(videos));
+  console.log(`Wrote ${videos.length} videos to ${file}`);
+};
+
+const generateSchedule = (maxDays: number = 7): Schedule => {
+  const loaded = loadVideos();
+  const days: number[] = [];
+  for (let day = 0; day <= maxDays; ++day) {
+    days.push(day);
+  }
+  const left: Video[][] = [];
+  const schedule: Schedule = {};
+  days.forEach((day) => {
+    schedule[getDay(day)] = {
+      categories: loaded.categories.map((categoryId: number) => {
+        const available: Video[] = left[categoryId]
+          ? left[categoryId]
+          : loaded.videos.filter((v) => v.categoryId === categoryId);
+        const videos: OrionVideo[] = selectVideos(available, 3); // select n videos
+        left[categoryId] = available.filter(
+          ({ videoId }) => !videos.find((v) => v.videoId === videoId)
+        );
+        return { categoryId, videos };
+      }),
+    };
+  });
+  return schedule;
+};
+
+const getCategoryFeaturedVideos = (): Promise<string> => {
+  //const headers = {};
+  const data =
+    '{ query: "query GetCategoriesFeaturedVideos {\n  allCategoriesFeaturedVideos {\n    categoryId\n    videos {\n      videoId\n      videoCutUrl\n    }\n  }\n}" }';
+  console.log(`sending`, data);
+  return axios
+    .post(orionUrl, data)
+    .then(({ data }: any) => JSON.stringify(data))
+    .catch((error: any) => error.message + JSON.stringify(error));
+};
+
+const setCategoryVideos = (categoryId: number, videos: OrionVideo[]): string =>
+  `mutation {
+    setCategoryFeaturedVideos(
+        categoryId: "${categoryId}"
+        videos: ${JSON.stringify(videos)}
+    ) {
+        videoId
+        videoCutUrl
+    }
+}`.replace(/\n/, "\n");
+
+const setCategoryFeaturedVideos = async (
+  categoryId: number,
+  videos: OrionVideo[]
+) => {
+  const headers = { Authorization: orionHeader };
+  const data = setCategoryVideos(categoryId, videos);
+  return console.log(`request`, data); // TODO remove after fixing request
+  axios
+    .post(orionUrl, { headers, data })
+    .then(async (res: any) => {
+      console.log(`sent post request to orion (${orionUrl})`, res);
+      //console.log(await getCategoryFeaturedVideos());
+    })
+    .catch((error: any) => {
+      console.error(
+        `Failed to set featured videos for category ${categoryId}: ${JSON.stringify(
+          error
+        )}`
+      );
+    });
+};
+
+const main = async (args: string[]) => {
+  switch (args[0]) {
+    case "get":
+      //const categoryId = Number(process.argv[2]);
+      console.log(await getCategoryFeaturedVideos());
+      break;
+    case "set":
+      try {
+        const schedule: Schedule = require(scheduleFile);
+        //console.log(getDay(), Object.keys(schedule));
+        if (!schedule || !schedule[getDay()]) {
+          console.error(`Current day not found in schedule. Run update again.`);
+          process.exit(1);
+        }
+        const { categories } = schedule[getDay()];
+        categories
+          .sort((a, b) => a.categoryId - b.categoryId)
+          .map(({ categoryId, videos }) =>
+            setCategoryFeaturedVideos(categoryId, videos)
+          );
+      } catch (e) {
+        console.warn(`Did you run: yarn run schedule`);
+      }
+      break;
+    case "schedule":
+      fs.writeFileSync(scheduleFile, JSON.stringify(generateSchedule()));
+      console.log(`Wrote schedule to ${scheduleFile}.`);
+      break;
+    case "update":
+      generateVideoList(videosFile);
+      break;
+    default:
+      console.log(`Available commands: [get, set, schedule, update]`);
+  }
+};
+main(process.argv.slice(2));

+ 0 - 42
working-groups/curator-group/featured/generateSchedule.js

@@ -1,42 +0,0 @@
-const fs = require("fs");
-
-const outfile = "schedule.txt";
-
-// load videos and extract category IDs
-const categories = [];
-const videos = require("./videos.json");
-videos.forEach(
-  ({ categoryId }) =>
-    categories.includes(categoryId) || categories.push(categoryId)
-);
-
-const selectVideos = (list, count) => {
-  let selected = [];
-  for (let n = 0; n < count; ++n) {
-    // remove selected videos
-    const available = list.filter((v) => !selected.includes(v));
-    // select random video
-    const id = Math.floor(Math.random() * available.length);
-    selected.push(available[id].videoId);
-  }
-  return selected;
-};
-
-// generate schedule
-let schedule = ``;
-categories.forEach((categoryId) => {
-  const list = videos.filter((v) => v && v.categoryId === categoryId);
-  const name = list[0].category;
-  schedule += `\nCategory ${categoryId}: ${name} (${list.length} videos):\n`;
-
-  // trim list to IDs for easier filtering
-  const available = list.map(({ videoId }) => videoId);
-
-  for (let day = 1; day <= 7; ++day) {
-    const featured = selectVideos(list, 3); // select n videos
-    const left = available.filter(({ videoId }) => !featured.includes(videoId));
-    schedule += `- Day ${day}: [ ${featured.join(", ")} ]\n`;
-  }
-});
-fs.writeFileSync(outfile, schedule);
-console.log(`Wrote schedule to ${outfile}`, schedule);

+ 21 - 0
working-groups/curator-group/featured/package.json

@@ -0,0 +1,21 @@
+{
+  "name": "jsfeatured",
+  "version": "0.0.1",
+  "description": "joystream-featured-categories",
+  "main": "categories.ts",
+  "scripts": {
+    "categories": "ts-node categories"
+  },
+  "repository": "https://github.com/Joystream/community-repo/",
+  "author": "l1dev",
+  "license": "MIT",
+  "private": false,
+  "devDependencies": {
+    "@types/node": "^16.11.12",
+    "axios": "^0.24.0",
+    "dotenv": "^10.0.0",
+    "moment": "^2.29.1",
+    "ts-node": "^10.4.0",
+    "typescript": "^4.5.3"
+  }
+}

+ 0 - 126
working-groups/curator-group/featured/schedule.txt

@@ -1,126 +0,0 @@
-
-Category 11: News _ Politics (12 videos):
-- Day 1: [ 6549, 6570, 6568 ]
-- Day 2: [ 6571, 6544, 6567 ]
-- Day 3: [ 6570, 6547, 6567 ]
-- Day 4: [ 6571, 6569, 6547 ]
-- Day 5: [ 6547, 6568, 6571 ]
-- Day 6: [ 6548, 6542, 6569 ]
-- Day 7: [ 6548, 6568, 6570 ]
-
-Category 6: Travel _ Events (9 videos):
-- Day 1: [ 2101, 2103, 2103 ]
-- Day 2: [ 1557, 2102, 1558 ]
-- Day 3: [ 1557, 2103, 2103 ]
-- Day 4: [ 1556, 2102, 1558 ]
-- Day 5: [ 2102, 1553, 2100 ]
-- Day 6: [ 2100, 1558, 1553 ]
-- Day 7: [ 1557, 1558, 2102 ]
-
-Category 10: Entertainment (Yes) (12 videos):
-- Day 1: [ 6620, 6618, 6625 ]
-- Day 2: [ 6621, 6619, 6621 ]
-- Day 3: [ 6624, 6620, 6621 ]
-- Day 4: [ 6626, 6618, 6625 ]
-- Day 5: [ 6624, 6625, 6622 ]
-- Day 6: [ 6617, 6627, 6623 ]
-- Day 7: [ 6628, 6622, 6624 ]
-
-Category 15: Nonprofits _ Activism (11 videos):
-- Day 1: [ 6521, 6519, 6518 ]
-- Day 2: [ 6519, 6520, 6522 ]
-- Day 3: [ 6520, 6515, 6515 ]
-- Day 4: [ 6521, 6520, 6523 ]
-- Day 5: [ 6520, 6516, 6521 ]
-- Day 6: [ 6523, 6513, 6517 ]
-- Day 7: [ 6516, 6523, 6513 ]
-
-Category 7: Gaming (Yes) (12 videos):
-- Day 1: [ 1996, 2150, 2145 ]
-- Day 2: [ 2137, 2142, 1996 ]
-- Day 3: [ 2137, 2145, 1992 ]
-- Day 4: [ 1992, 2120, 2150 ]
-- Day 5: [ 2113, 2108, 2118 ]
-- Day 6: [ 2113, 1992, 2125 ]
-- Day 7: [ 2120, 2113, 2120 ]
-
-Category 1: Film _ Animation (Yes) (12 videos):
-- Day 1: [ 788, 109, 788 ]
-- Day 2: [ 790, 115, 352 ]
-- Day 3: [ 109, 305, 3 ]
-- Day 4: [ 117, 3, 117 ]
-- Day 5: [ 798, 305, 117 ]
-- Day 6: [ 352, 117, 3 ]
-- Day 7: [ 798, 114, 109 ]
-
-Category 2: Autos _ Vehicles (12 videos):
-- Day 1: [ 6538, 6532, 6535 ]
-- Day 2: [ 6533, 6539, 6537 ]
-- Day 3: [ 6533, 6533, 6537 ]
-- Day 4: [ 6537, 6538, 6535 ]
-- Day 5: [ 6540, 6539, 6537 ]
-- Day 6: [ 6536, 6536, 6540 ]
-- Day 7: [ 6532, 6539, 6540 ]
-
-Category 5: Sports (Yes) (12 videos):
-- Day 1: [ 6529, 792, 254 ]
-- Day 2: [ 6525, 6528, 241 ]
-- Day 3: [ 6524, 6525, 6526 ]
-- Day 4: [ 6526, 6530, 792 ]
-- Day 5: [ 6527, 6528, 792 ]
-- Day 6: [ 6562, 6562, 6524 ]
-- Day 7: [ 241, 6525, 254 ]
-
-Category 9: Comedy (12 videos):
-- Day 1: [ 6664, 6661, 6670 ]
-- Day 2: [ 6666, 6664, 6669 ]
-- Day 3: [ 6671, 6667, 6666 ]
-- Day 4: [ 6668, 6670, 6662 ]
-- Day 5: [ 6661, 6667, 6668 ]
-- Day 6: [ 6664, 6668, 6668 ]
-- Day 7: [ 6668, 6666, 6661 ]
-
-Category 4: Pets _ Animals (10 videos):
-- Day 1: [ 489, 544, 6643 ]
-- Day 2: [ 248, 6641, 1675 ]
-- Day 3: [ 543, 6647, 489 ]
-- Day 4: [ 6647, 248, 543 ]
-- Day 5: [ 543, 6640, 6643 ]
-- Day 6: [ 544, 543, 543 ]
-- Day 7: [ 6640, 543, 489 ]
-
-Category 13: Education (12 videos):
-- Day 1: [ 6638, 6630, 6638 ]
-- Day 2: [ 6635, 6630, 6633 ]
-- Day 3: [ 6637, 6630, 6634 ]
-- Day 4: [ 6638, 6635, 6632 ]
-- Day 5: [ 6629, 6631, 6633 ]
-- Day 6: [ 6636, 6634, 6637 ]
-- Day 7: [ 6633, 2159, 6635 ]
-
-Category 14: Science _ Technology (12 videos):
-- Day 1: [ 310, 340, 340 ]
-- Day 2: [ 310, 340, 6579 ]
-- Day 3: [ 329, 310, 6576 ]
-- Day 4: [ 6574, 6577, 6574 ]
-- Day 5: [ 310, 6581, 6573 ]
-- Day 6: [ 6580, 6576, 310 ]
-- Day 7: [ 6580, 329, 1093 ]
-
-Category 3: Music (12 videos):
-- Day 1: [ 6591, 6587, 6592 ]
-- Day 2: [ 11, 6588, 11 ]
-- Day 3: [ 6590, 11, 6590 ]
-- Day 4: [ 6592, 6588, 6583 ]
-- Day 5: [ 11, 6591, 6592 ]
-- Day 6: [ 6584, 6582, 6583 ]
-- Day 7: [ 6583, 6592, 6587 ]
-
-Category 12: Howto _ Style (11 videos):
-- Day 1: [ 2046, 2053, 2045 ]
-- Day 2: [ 2046, 2045, 674 ]
-- Day 3: [ 777, 786, 2067 ]
-- Day 4: [ 2067, 2046, 2068 ]
-- Day 5: [ 786, 2067, 674 ]
-- Day 6: [ 2046, 2045, 2068 ]
-- Day 7: [ 2066, 2067, 2068 ]

+ 21 - 0
working-groups/curator-group/featured/types.ts

@@ -0,0 +1,21 @@
+export interface Video {
+  videoId: number;
+  category: string;
+  categoryId: number;
+  count: number;
+}
+
+export interface OrionVideo {
+  videoId: number;
+  videoCutUrl: string;
+}
+
+export interface Category {
+  categoryId: number;
+  videos: OrionVideo[];
+}
+
+export interface Schedule {
+  [key: string]: { categories: Category[] };
+}
+

+ 0 - 20
working-groups/curator-group/featured/updateVideos.js

@@ -1,20 +0,0 @@
-const fs = require("fs");
-
-const outfile = `videos.json`
-
-const videos = fs
-  .readFileSync(`./list`, `utf-8`)
-  .split(`\n`)
-  .map((path) => {
-    // ./Howto _ Style 11/12-2066.mp4
-    const match = path.match(/\.\/([^\/]+) (\d+)\/(\d+)-(\d+)\.mp4/);
-    if (match) {
-      const category = match[1];
-      const count = match[2];
-      const categoryId = match[3];
-      const videoId = match[4];
-      return { category, count, categoryId, videoId };
-    }
-  }).filter(v=>v)
-fs.writeFileSync(outfile, JSON.stringify(videos));
-console.log(`Wrote ${videos.length} videos to ${outfile}`);