252 lines
9.1 KiB
Vue
252 lines
9.1 KiB
Vue
<template>
|
|
<div>
|
|
<div class="grid-x">
|
|
<div class="medium-7 cell"></div>
|
|
<div class="medium-1 cell">
|
|
<button type="button" class="button input-group" v-on:click='importchannel'>
|
|
<i class="fa fa-plus" aria-hidden="true"></i> Import
|
|
</button>
|
|
</div>
|
|
<div class="medium-1 cell"></div>
|
|
<div class="medium-1 cell">
|
|
<button type="button" class="button input-group" v-on:click='exportchannel'>
|
|
<i class="fa fa-plus" aria-hidden="true"></i> Export
|
|
</button>
|
|
</div>
|
|
<div class="medium-1 cell"></div>
|
|
<div class="medium-1 cell">
|
|
<button type="button" class="button input-group" v-on:click='Expanded = !Expanded'>
|
|
<i class="fa fa-plus" aria-hidden="true"></i> Add
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<transition name="fade">
|
|
<form v-cloak v-if="Expanded">
|
|
<h2>Add new Channel</h2>
|
|
<div class="grid-x">
|
|
<div class="medium-7 cell">
|
|
<p class="input-group">
|
|
<span class="input-group-label">Title</span>
|
|
<input class="input-group-field" type="text" placeholder="Youtube Channel Title"
|
|
v-model="Title" readonly>
|
|
</p>
|
|
<p class="input-group">
|
|
<span class="input-group-label">Channel ID</span>
|
|
<input class="input-group-field" v-bind:class="{ error: !Valid }" type="text"
|
|
placeholder="https://www.youtube.com/channel/UCJkMlOu7faDgqh4PfzbpLdg"
|
|
v-model="Channel_Identification_Box">
|
|
</p>
|
|
<p class="input-group">
|
|
<span class="input-group-label">Description</span>
|
|
<input class="input-group-field" placeholder="Description"
|
|
v-model="Description" readonly cols="15" rows="5"
|
|
type="text">
|
|
</p>
|
|
<button type="button"
|
|
class="button input-group" style="max-height:50px; max-width:100px; float: right;"
|
|
v-if="Valid" @click="Submit">Submit</button>
|
|
</div>
|
|
<div class="medium-2 cell"></div>
|
|
<div class="input-group medium-2 cell">
|
|
<img :src="Thumbnail"/>
|
|
</div>
|
|
<div class="medium-1 cell"></div>
|
|
</div>
|
|
</form>
|
|
</transition>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import Vue from "vue";
|
|
import * as DumbYT from "../dumbyt";
|
|
import Axios from "axios";
|
|
import SA2,{ SweetAlertType } from "sweetalert2";
|
|
import * as _ from "lodash";
|
|
import Sweetalert2, {SweetAlertOptions} from "sweetalert2";
|
|
|
|
// Small wrapper to convert to and from channels and import/export possible channels.
|
|
class OutChannel {
|
|
ID : string;
|
|
Tags : Array<string>;
|
|
Title: string;
|
|
|
|
constructor(channel :DumbYT.Channel) {
|
|
this.ID = channel.ID;
|
|
this.Title = channel.Title;
|
|
this.Tags = channel.User_Tags;
|
|
}
|
|
};
|
|
|
|
async function Channel_Bulk_Add() : Promise<void> {
|
|
// Ask user for the JSON file containing our channels.
|
|
const {value: uploadedfile} = await SA2({
|
|
title: 'Select image',
|
|
input: 'file',
|
|
inputAttributes: {
|
|
'aria-label': 'Upload your profile picture'
|
|
}
|
|
});
|
|
|
|
// Check that we got an input file.
|
|
if (uploadedfile != null) {
|
|
// Read our file.
|
|
var reader = new FileReader();
|
|
|
|
// Tell reader to run upload our channels when it got a file.
|
|
reader.onload = async (e) => {
|
|
// Send all requested channel updates to the server.
|
|
const channels = JSON.parse(reader.result) as OutChannel[];
|
|
const attempts = await Promise.all(channels.map(c => DumbYT.API.channel_modify(c.ID, DumbYT.API.Modification.Add)));
|
|
|
|
// Get all the insertions which failed.
|
|
const bad = attempts.filter((a: any): a is string => !!a).map(a => {return {
|
|
title: "Channel Add Fail!",
|
|
text: "The channel has not been added due to the following: \n" + a,
|
|
type: "error"} as SweetAlertOptions
|
|
});
|
|
|
|
// Make dialog boxes for them.
|
|
await SA2.queue(bad);
|
|
}
|
|
|
|
// Give our uploader the data which was sent.
|
|
reader.readAsText(uploadedfile)
|
|
}
|
|
}
|
|
|
|
// Vue class for keeping state of the videos.
|
|
export default Vue.extend({
|
|
data() {
|
|
return {
|
|
Title: "",
|
|
Description: "",
|
|
ID: "",
|
|
Thumbnail: "",
|
|
Valid: false,
|
|
Expanded: false,
|
|
Channel_Identification_Box : ""
|
|
}
|
|
},
|
|
|
|
watch: {
|
|
Channel_Identification_Box(newcontents: string) {
|
|
this.GetChannelFromYT(newcontents);
|
|
}
|
|
},
|
|
methods: {
|
|
Submit() : void {
|
|
DumbYT.API.channel_modify(this.ID, DumbYT.API.Modification.Add).then((resp) => {
|
|
if (resp == null)
|
|
SA2(
|
|
"Channel Add Success!",
|
|
"The channel has been added succesfully, video contents should be updated shortly.",
|
|
"success"
|
|
);
|
|
else
|
|
SA2(
|
|
"Channel Add Fail!",
|
|
"The channel has not been added due to the following: \n" + resp,
|
|
"error"
|
|
);
|
|
});
|
|
|
|
// Hide the bars and erase internal state.
|
|
this.Expanded = false;
|
|
this.clear();
|
|
},
|
|
|
|
// Clears the contents of the add channel field
|
|
clear() : void {
|
|
this.Title = "";
|
|
this.Description = "";
|
|
this.ID = "";
|
|
this.Thumbnail = "";
|
|
this.Valid = false;
|
|
this.Channel_Identification_Box = "";
|
|
},
|
|
|
|
// Export the channels as a json file.
|
|
exportchannel() : void {
|
|
function download(filename: string, text: string) : void {
|
|
var element = document.createElement('a');
|
|
element.setAttribute('href', 'data:application/json;charset=utf-8,' + encodeURIComponent(text));
|
|
element.setAttribute('download', filename);
|
|
|
|
element.style.display = 'none';
|
|
document.body.appendChild(element);
|
|
|
|
element.click();
|
|
|
|
document.body.removeChild(element);
|
|
}
|
|
|
|
// Get all the youtube channels.
|
|
DumbYT.API.search_channels("").then(channels =>
|
|
download("Channel_Export.json",
|
|
JSON.stringify(channels.map(c => new OutChannel(c)))
|
|
)
|
|
);
|
|
},
|
|
|
|
// Import a channel list
|
|
importchannel() : void {
|
|
Channel_Bulk_Add();
|
|
},
|
|
|
|
GetChannelFromYT(Channel: string) : void {
|
|
// Say it failed first so if we exit early then correctly marked fail.
|
|
this.Title = "";
|
|
this.Description = "";
|
|
this.ID = "";
|
|
this.Thumbnail = "";
|
|
this.Valid = false;
|
|
|
|
// Remove possible channel inputs.
|
|
// https://www.youtube.com/channel/UC2DjFE7Xf11URZqWBigcVOQ
|
|
// UC2DjFE7Xf11URZqWBigcVOQ
|
|
// https://www.youtube.com/user/EEVblog <-- Take first channel found
|
|
// EEVblog <-- Take first channel found
|
|
|
|
// Remove any potential youtube URL from the field.
|
|
Channel = Channel.replace("https://www.youtube.com", "");
|
|
Channel = Channel.replace("/channel/", "");
|
|
Channel = Channel.replace("/user/", "");
|
|
|
|
// Get channel metadata.
|
|
const API = 'https://www.googleapis.com/youtube/v3/channels/?';
|
|
const API_Parts = 'part=snippet';
|
|
const API_Key = '&key=AIzaSyCuIYkMc5SktlnXRXNaDf2ObX-fQvtWCnQ'
|
|
const API_Search_Query =
|
|
((Channel.length == "UCyS4xQE6DK4_p3qXQwJQAyA".length) ? "&id=" : "&forUsername=")
|
|
+ Channel;
|
|
Axios.get(API + API_Parts + API_Search_Query + API_Key).then((resp) => {
|
|
this.ID = resp.data.items[0].id;
|
|
this.Description = _.truncate(resp.data.items[0].snippet.description, {length: 70});
|
|
this.Title = resp.data.items[0].snippet.title;
|
|
this.Thumbnail = resp.data.items[0].snippet.thumbnails.high.url;
|
|
this.Valid = true;
|
|
})
|
|
.catch(function (error) {
|
|
console.log(error);
|
|
});
|
|
}
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<style>
|
|
.fade-enter-active {
|
|
transition: opacity 0.75s;
|
|
}
|
|
|
|
.fade-leave-active {
|
|
transition: opacity 0.25s;
|
|
}
|
|
|
|
.fade-enter, .fade-leave-to {
|
|
opacity: 0;
|
|
}
|
|
</style>
|