123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- 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 data = {
- query:
- "query GetCategoriesFeaturedVideos {\n allCategoriesFeaturedVideos {\n categoryId\n videos {\n videoId\n videoCutUrl\n }\n }\n}",
- };
- return axios
- .post(orionUrl, data)
- .then(({ data }: any) => {
- fs.writeFileSync(`featured.json`, JSON.stringify(data));
- console.log(`Wrote featured.json`);
- return data;
- })
- .catch((error: any) => error.message + error);
- };
- const setCategoryVideos = (categoryId: number): string =>
- `
- mutation SetFeaturedVideos ($videos: [FeaturedVideoInput!]!) {
- setCategoryFeaturedVideos(categoryId: "${categoryId}", videos: $videos) {
- videoId
- videoCutUrl
- }
- }
- `;
- const setCategoryFeaturedVideos = async (
- categoryId: number,
- videos: OrionVideo[]
- ) => {
- const headers = { Authorization: orionHeader };
- const query = setCategoryVideos(categoryId);
- axios
- .post(orionUrl, { query, variables: { videos } }, { headers })
- .then(async ({ status, statusText }: any) =>
- console.log(`Set videos for category ${categoryId}:`, status, statusText)
- )
- .catch((error: any) => {
- console.error(
- `Failed to set featured videos for category ${categoryId}:`,
- error.response.data.errors.map(
- (e: any) => e.message + JSON.stringify(e.locations)
- )
- );
- process.exit(1);
- });
- };
- const main = async (args: string[]) => {
- switch (args[0]) {
- case "get":
- getCategoryFeaturedVideos();
- break;
- case "set":
- try {
- const schedule: Schedule = require(scheduleFile);
- 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));
|