Removed frontend and moved out of sln into solely csproj style
This commit is contained in:
parent
dc1937d2f8
commit
a3e7b4f8f7
@ -4,7 +4,7 @@ using Hangfire.Storage;
|
||||
|
||||
namespace YTManager.Controllers {
|
||||
[Produces("application/json")]
|
||||
[Route("api/Admin")]
|
||||
[Route("api/admin")]
|
||||
public class AdminController : Controller {
|
||||
// Get the mass update daemon job.
|
||||
private static RecurringJobDto get_massupdatedaemon() {
|
@ -1,25 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26730.12
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YTManager", "YTManager\YTManager.csproj", "{14F56CC1-67A1-477F-817C-A0A7B55AE954}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{14F56CC1-67A1-477F-817C-A0A7B55AE954}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{14F56CC1-67A1-477F-817C-A0A7B55AE954}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{14F56CC1-67A1-477F-817C-A0A7B55AE954}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{14F56CC1-67A1-477F-817C-A0A7B55AE954}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {DB293C09-A2E4-4179-ADA9-BAE2093F425A}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@ -1,39 +0,0 @@
|
||||
|
||||
ASP.NET MVC core dependencies have been added to the project.
|
||||
(These dependencies include packages required to enable scaffolding)
|
||||
|
||||
However you may still need to do make changes to your project.
|
||||
|
||||
1. Suggested changes to Startup class:
|
||||
1.1 Add a constructor:
|
||||
public IConfiguration Configuration { get; }
|
||||
|
||||
public Startup(IConfiguration configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
}
|
||||
1.2 Add MVC services:
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
// Add framework services.
|
||||
services.AddMvc();
|
||||
}
|
||||
|
||||
1.3 Configure web app to use use Configuration and use MVC routing:
|
||||
|
||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
|
||||
{
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
|
||||
app.UseStaticFiles();
|
||||
|
||||
app.UseMvc(routes =>
|
||||
{
|
||||
routes.MapRoute(
|
||||
name: "default",
|
||||
template: "{controller=Home}/{action=Index}/{id?}");
|
||||
});
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>YT Manager Admin</title>
|
||||
|
||||
<!-- Compressed CSS -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.4.3/css/foundation.min.css" />
|
||||
</head>
|
||||
<body>
|
||||
<h2>Admin Page</h2>
|
||||
<div id="admin_app"></div>
|
||||
<script src="./../dist/build.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,20 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>YT Manager</title>
|
||||
|
||||
<!-- Compressed CSS -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.4.3/css/foundation.min.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="pageheader">
|
||||
<h1>Dumb YT Manager</h1>
|
||||
<p>Youtube banned my account and refuses to say why, taking all my subscribed channels with it. This is a simple scrubscribed channel manager, showing recent releases from each channel and finally proper sub-catagory functionality!</p>
|
||||
</div>
|
||||
|
||||
<div id="app"></div>
|
||||
|
||||
<script src="./dist/build.js"></script>
|
||||
</body>
|
||||
</html>
|
10969
YTManager/frontend/package-lock.json
generated
10969
YTManager/frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,31 +0,0 @@
|
||||
{
|
||||
"name": "dumbytmanager",
|
||||
"version": "0.1.0",
|
||||
"description": "Front end for the DumbYT Manager project",
|
||||
"main": "index.js",
|
||||
"repository": "https://gitea.hak8or.com/Almost_There/dumbytmanager",
|
||||
"author": "hak8or",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/lodash": "^4.14.104",
|
||||
"axios": "^0.18.0",
|
||||
"css-loader": "^0.28.10",
|
||||
"style-loader": "^0.20.2",
|
||||
"sweetalert2": "^7.13.3",
|
||||
"ts-loader": "^4.0.0",
|
||||
"typescript": "^2.7.2",
|
||||
"uglifyjs-webpack-plugin": "^1.2.2",
|
||||
"vue": "^2.5.13",
|
||||
"vue-loader": "^14.1.1",
|
||||
"vue-template-compiler": "^2.5.13",
|
||||
"webpack": "^4.0.1",
|
||||
"webpack-cli": "^2.0.9",
|
||||
"webpack-dev-server": "^3.1.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "webpack-dev-server --mode development --open",
|
||||
"dev": "webpack --mode development",
|
||||
"build": "webpack --mode production",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
# Frontend
|
||||
|
||||
## Description
|
||||
Oh god, front end web development, specifically javascript.
|
||||
|
||||
This project makes use of the following:
|
||||
|
||||
- Vuejs
|
||||
Seemingly resonable javascript framework that's well documented and actively developed.
|
||||
|
@ -1,126 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="grid-x">
|
||||
<div class="medium-11 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="input-group medium-6 cell">
|
||||
<span class="input-group-label">Title</span>
|
||||
<input class="input-group-field" type="text" placeholder="Title" v-model="Title">
|
||||
</div>
|
||||
<div class="input-group medium-1 cell"></div>
|
||||
<div class="input-group medium-5 cell">
|
||||
<span class="input-group-label">Channel</span>
|
||||
<input class="input-group-field" v-bind:class="{ error: !Valid }" type="text"
|
||||
placeholder="URL" v-model="Channel_Identification_Box">
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<span class="input-group-label">Description</span>
|
||||
<input class="input-group-field" type="text" placeholder="Description" v-model="Description">
|
||||
</div>
|
||||
<div class="grid-x">
|
||||
<img class="small-4 cell" :src="Thumbnail" />
|
||||
<div class="small-7"></div>
|
||||
<button type="button" style="max-height:50px" class="button input-group small-1 cell" @click="Submit">Submit</button>
|
||||
</div>
|
||||
</form>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import * as Dyt from "../dumbyt";
|
||||
import Axios from "axios";
|
||||
import SA2 from "sweetalert2";
|
||||
|
||||
// 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 {
|
||||
Dyt.channel_modify(this.ID, Dyt.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.Title = "";
|
||||
this.Description = "";
|
||||
this.ID = "";
|
||||
this.Thumbnail = "";
|
||||
this.Valid = false;
|
||||
this.Channel_Identification_Box = "";
|
||||
},
|
||||
|
||||
GetChannelFromYT(Channel: string) : void {
|
||||
// Say it failed first so if we exit early then correctly marked fail.
|
||||
this.Valid = false;
|
||||
|
||||
// Copy over to internal ID box.
|
||||
this.ID = Channel;
|
||||
|
||||
// Remove any potential youtube URL from the field.
|
||||
const ytchurl = "https://www.youtube.com/channel/";
|
||||
if (this.ID.startsWith(ytchurl))
|
||||
this.ID = this.ID.replace(ytchurl, "");
|
||||
|
||||
// Check if what remains looks like a youtube channel ID.
|
||||
if (this.ID.length != "UCyS4xQE6DK4_p3qXQwJQAyA".length)
|
||||
return;
|
||||
|
||||
// Get channel metadata.
|
||||
const API = 'https://www.googleapis.com/youtube/v3/channels?';
|
||||
const API_Parts = 'part=snippet%2CcontentDetails%2Cstatistics';
|
||||
const API_Key = '&key=AIzaSyCuIYkMc5SktlnXRXNaDf2ObX-fQvtWCnQ'
|
||||
const API_Search_ID = '&id=' + this.ID;
|
||||
Axios.get(API + API_Parts + API_Search_ID + API_Key).then((resp) => {
|
||||
this.Description = resp.data.items[0].snippet.description;
|
||||
this.Title = resp.data.items[0].snippet.title;
|
||||
this.Thumbnail = resp.data.items[0].snippet.thumbnails.medium.url;
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
@ -1,40 +0,0 @@
|
||||
<template>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Title</th>
|
||||
<th>Description</th>
|
||||
<th>User Tags</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-cloak v-for="channel in Channels" :key=channel.ID class="Grid_Small_Text">
|
||||
<td>{{channel.ID}}</td>
|
||||
<td>{{channel.Title}}</td>
|
||||
<td>{{channel.Description}}</td>
|
||||
<td>{{channel.User_Tags}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue, {PropOptions} from "vue";
|
||||
import * as Dyt from "../dumbyt";
|
||||
|
||||
// Vue class for keeping state of the videos.
|
||||
export default Vue.extend({
|
||||
props: {
|
||||
Channels: {
|
||||
type: Array,
|
||||
} as PropOptions<Dyt.Channel[]>,
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.Grid_Small_Text {
|
||||
font-size: 0.7em;
|
||||
}
|
||||
</style>
|
@ -1,45 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<input id="searchbox0" class="searchbox" type="text" v-model="searchbox_str"
|
||||
placeholder="Search String goes here, for example: >5m,c++"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue, {PropOptions} from "vue";
|
||||
import * as _ from "lodash";
|
||||
import * as Dyt from "../dumbyt";
|
||||
|
||||
// Vue class for keeping state of the videos.
|
||||
export default Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
searchbox_str: "",
|
||||
}
|
||||
},
|
||||
|
||||
// Manually attaching functions to watchers of data.
|
||||
watch: {
|
||||
// Searchbox updater with debouncing.
|
||||
searchbox_str (s: string) {
|
||||
var v = _.debounce((s) => {
|
||||
Dyt.search_videos(s).then(videos => {
|
||||
this.$emit('search_complete', videos)
|
||||
});
|
||||
}, 400)
|
||||
v(s);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.searchbox {
|
||||
font-size: 1.2em;
|
||||
max-width: 40em;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 2em;
|
||||
}
|
||||
</style>
|
@ -1,52 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="grid-x large-up-6">
|
||||
<div v-for="video in Videos" :key="video.ID" class="cell">
|
||||
<div class="card ytcard">
|
||||
<a :href="video.URL"><img :src="video.Thumbnail"></a>
|
||||
<div class="card-section description">
|
||||
<div class="descriptiontitle">{{ video.Title }}</div>
|
||||
<div class="descriptionchannel">{{ video.Channel }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div >
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue, {PropOptions} from "vue";
|
||||
import * as Dyt from "../dumbyt";
|
||||
|
||||
// Vue class for keeping state of the videos.
|
||||
export default Vue.extend({
|
||||
props: {
|
||||
Videos: {
|
||||
type: Array,
|
||||
} as PropOptions<Dyt.Video[]>,
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.ytcard {
|
||||
border-bottom-left-radius: 10px;
|
||||
border-bottom-right-radius: 10px;
|
||||
background-color:#ddd9d4;
|
||||
margin: 6px 2px 6px;
|
||||
}
|
||||
|
||||
.description {
|
||||
padding: 7px 5px 7px;
|
||||
}
|
||||
|
||||
.descriptiontitle {
|
||||
font-size: 14px;
|
||||
padding-bottom:10px;
|
||||
}
|
||||
|
||||
.descriptionchannel {
|
||||
font-size: 10px;
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
@ -1,43 +0,0 @@
|
||||
<template>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Title</th>
|
||||
<th>Channel</th>
|
||||
<th>Seconds</th>
|
||||
<th>Tags</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-cloak v-for="video in Videos" :key=video.ID class="Grid_Small_Text">
|
||||
<td>{{video.ID}}</td>
|
||||
<td>{{video.Title}}</td>
|
||||
<td>{{video.Channel}}</td>
|
||||
<td>{{video.Seconds}}</td>
|
||||
<td>{{video.Tags}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue, {PropOptions} from "vue";
|
||||
import * as Dyt from "../dumbyt";
|
||||
|
||||
// Vue class for keeping state of the videos.
|
||||
export default Vue.extend({
|
||||
props: {
|
||||
Videos: {
|
||||
type: Array,
|
||||
} as PropOptions<Dyt.Video[]>,
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.Grid_Small_Text {
|
||||
font-size: 0.7em;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,210 +0,0 @@
|
||||
import Axios from "axios";
|
||||
|
||||
// Base URL for API queries.
|
||||
const API_BASE_URL = "/api";
|
||||
|
||||
// How many chars at most for the description.
|
||||
const max_description_length = 100;
|
||||
|
||||
// Wrapper for channels returned from our server.
|
||||
export class Channel {
|
||||
// Title of the channel according to youtube.
|
||||
public Title: string;
|
||||
|
||||
// Description of channel according to youtube.
|
||||
public Description: string;
|
||||
|
||||
// Youtube ID
|
||||
public ID: string;
|
||||
|
||||
// Tags given to the video.
|
||||
public User_Tags: Array<string>;
|
||||
|
||||
// ID's belonging to the channel.
|
||||
public Video_IDs: Array<string>;
|
||||
|
||||
// Popuplate this using data from our server.
|
||||
constructor(c : any){
|
||||
if (c == null) {
|
||||
this.Title = "NULL"
|
||||
this.Description = "NULL"
|
||||
this.ID = "NULL"
|
||||
this.User_Tags = ["NULL", "NULL", "NULL"]
|
||||
this.Video_IDs = ["NULL", "NULL"]
|
||||
} else {
|
||||
this.Title = c.title;
|
||||
this.Description = c.description;
|
||||
this.ID = c.id;
|
||||
this.User_Tags = c.user_Tags;
|
||||
this.Video_IDs = c.video_IDs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper for videos returned from our server.
|
||||
export class Video {
|
||||
// Title of the video according to youtube.
|
||||
public Title: string;
|
||||
|
||||
// Description of video according to youtube.
|
||||
public Description: string;
|
||||
|
||||
// Youtube ID
|
||||
public ID: string;
|
||||
|
||||
// Thumbnail
|
||||
public Thumbnail: string;
|
||||
|
||||
// What channel made this video.
|
||||
public Channel: string;
|
||||
|
||||
// Duration of the video in seconds.
|
||||
public Seconds: number;
|
||||
|
||||
// Tags relevant to the video.
|
||||
public Tags: Array<string>;
|
||||
|
||||
// Youtube URL of the video.
|
||||
public URL: string;
|
||||
|
||||
// Popuplate this using data from our server.
|
||||
constructor(v: any){
|
||||
if (v == null){
|
||||
this.Title = "NULL";
|
||||
this.Description = "NULL";
|
||||
this.ID = "NULL";
|
||||
this.Thumbnail = "NULL";
|
||||
this.Channel = "NULL";
|
||||
this.Seconds = 9999999;
|
||||
this.Tags = ["NULL", "NULL"];
|
||||
this.URL = "NULL";
|
||||
} else {
|
||||
this.Title = v.title;
|
||||
this.Description = v.description;
|
||||
this.ID = v.id;
|
||||
this.Thumbnail = v.thumbnail;
|
||||
this.Channel = v.channel;
|
||||
this.Seconds = v.seconds;
|
||||
this.Tags = v.tags;
|
||||
this.URL = "https://www.youtube.com/watch?v=" + v.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Types of modifications which can be applied to various models.
|
||||
export enum Modification {
|
||||
Add, Delete, Refresh
|
||||
}
|
||||
|
||||
// Change a channel state.
|
||||
export async function channel_modify(youtubeID : string, modify : Modification): Promise<void | string> {
|
||||
switch (modify){
|
||||
case Modification.Add: {
|
||||
let URL = API_BASE_URL + '/Channels/' + youtubeID;
|
||||
let resp = await Axios.post(URL).catch((error) => {
|
||||
if (error.response)
|
||||
return error.response.data;
|
||||
else if (error.request)
|
||||
return error.request;
|
||||
else
|
||||
return "Axios request failed for unkown reason.";
|
||||
});
|
||||
if (typeof resp == "string")
|
||||
return resp;
|
||||
break;
|
||||
}
|
||||
case Modification.Delete: {
|
||||
let URL = API_BASE_URL + '/Channels/' + youtubeID;
|
||||
let resp = await Axios.delete(URL).catch(e => console.log(e));
|
||||
if (resp != null){
|
||||
if (resp.status != 200)
|
||||
return resp.data();
|
||||
else
|
||||
return;
|
||||
} else {
|
||||
return "Response is null";
|
||||
}
|
||||
}
|
||||
case Modification.Refresh: {
|
||||
let URL = API_BASE_URL + '/Channels/Update/' + youtubeID;
|
||||
let resp = await Axios.post(URL).catch(e => console.log(e));
|
||||
if (resp != null){
|
||||
if (resp.status != 200)
|
||||
return resp.data();
|
||||
else
|
||||
return;
|
||||
} else {
|
||||
return "Response is null";
|
||||
}
|
||||
}
|
||||
default: {
|
||||
console.log("Unknown request type, error ...");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete a video.
|
||||
export async function video_delete(youtubeID : string) : Promise<void> {
|
||||
let URL = API_BASE_URL + '/Videos/' + youtubeID;
|
||||
let resp = await Axios.delete(URL).catch(e => console.log(e));
|
||||
if ((resp == null) || (resp.data == null)){
|
||||
console.log("Video delete via " + URL + " FAIL");
|
||||
};
|
||||
}
|
||||
|
||||
// Search for channels based on a search string.
|
||||
export async function search_channels(searchstr : string): Promise<Array<Channel>> {
|
||||
// Temporary holder for data.
|
||||
let Channels : Array<Channel> = [];
|
||||
|
||||
// Ask server for data.
|
||||
let resp = await Axios.get(API_BASE_URL + '/Channels/' + searchstr).catch(e => console.log(e));
|
||||
|
||||
// Handle all our nulls.
|
||||
if (resp == null || resp.data == null)
|
||||
console.log("server /api/Channels/" + searchstr + " return is null");
|
||||
else {
|
||||
// Parse our videos.
|
||||
resp.data.forEach((c: any) => {
|
||||
// Trim description if needed.
|
||||
if (c.description.length > max_description_length) {
|
||||
c.description = c.description.substring(0, max_description_length) + " ...";
|
||||
}
|
||||
|
||||
// Add it to our array
|
||||
Channels.push(new Channel(c));
|
||||
});
|
||||
}
|
||||
|
||||
// Send back the resulting videos.
|
||||
return Promise.resolve(Channels);
|
||||
}
|
||||
|
||||
// Search for videos based on a search string.
|
||||
export async function search_videos(searchstr : string): Promise<Array<Video>> {
|
||||
// Temporary holder for videos.
|
||||
let Videos : Array<Video> = [];
|
||||
|
||||
// Ask server for videos.
|
||||
let resp = await Axios.get(API_BASE_URL + '/Videos/' + searchstr).catch(e => console.log(e));
|
||||
|
||||
// Handle all our nulls.
|
||||
if (resp == null || resp.data == null)
|
||||
console.log("server /videos/ return is null");
|
||||
else {
|
||||
// Parse our videos.
|
||||
resp.data.forEach((v: any) => {
|
||||
// Trim description if needed.
|
||||
if (v.description.length > max_description_length) {
|
||||
v.description = v.description.substring(0, max_description_length) + " ...";
|
||||
}
|
||||
|
||||
// Add it to our array
|
||||
Videos.push(new Video(v));
|
||||
});
|
||||
}
|
||||
|
||||
// Send back the resulting videos.
|
||||
return Promise.resolve(Videos);
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
body {
|
||||
margin-left: 5%;
|
||||
margin-right: 5%;
|
||||
line-height: 1.6;
|
||||
font-size: 18px;
|
||||
color: #003636;
|
||||
background-color: #F8F8F8;
|
||||
max-width: 1280px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.pageheader {
|
||||
max-width: 960px;
|
||||
margin: auto;
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
import Vue from "vue";
|
||||
import VGC from "./components/Video_Grid.vue";
|
||||
import SCH from "./components/Search.vue";
|
||||
import VTBL from "./components/Video_Table.vue";
|
||||
import CTBL from "./components/Channel_Table.vue";
|
||||
import CADD from "./components/Channel_Add.vue";
|
||||
import './index.css';
|
||||
import { Video, search_videos, Channel, search_channels } from "./dumbyt";
|
||||
|
||||
let MainApp = new Vue({
|
||||
el: "#app",
|
||||
template: `
|
||||
<div>
|
||||
<SCH v-on:search_complete="search_completed"/>
|
||||
<VGC v-bind:Videos="Videos"/>
|
||||
</div>
|
||||
`,
|
||||
components: {
|
||||
SCH,
|
||||
VGC
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
Videos: Array<Video>()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// Callback for when the search component got results back.
|
||||
search_completed(videos : Array<Video>) : void {
|
||||
this.Videos = videos;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let AdminApp = new Vue({
|
||||
el: "#admin_app",
|
||||
template: `
|
||||
<div>
|
||||
<SCH v-on:search_complete="search_completed"/>
|
||||
<CADD/>
|
||||
<CTBL v-bind:Channels="Channels"/>
|
||||
<VTBL v-bind:Videos="Videos"/>
|
||||
</div>
|
||||
`,
|
||||
components: {
|
||||
SCH,
|
||||
CADD,
|
||||
CTBL,
|
||||
VTBL
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
Videos: Array<Video>(),
|
||||
Channels: Array<Channel>()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// Callback for when the search component got results back.
|
||||
search_completed(videos : Array<Video>) : void {
|
||||
this.Videos = videos;
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
// Populate the channels field immediatly on start up.
|
||||
search_channels("").then(channels => this.Channels = channels);
|
||||
}
|
||||
});
|
4
YTManager/frontend/src/vue-shims.d.ts
vendored
4
YTManager/frontend/src/vue-shims.d.ts
vendored
@ -1,4 +0,0 @@
|
||||
declare module "*.vue" {
|
||||
import Vue from "vue";
|
||||
export default Vue;
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "./built/",
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"noImplicitReturns": true,
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"target": "es6",
|
||||
"noImplicitAny": true
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*"
|
||||
]
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
var path = require('path')
|
||||
var webpack = require('webpack')
|
||||
|
||||
module.exports = {
|
||||
entry: './src/index.ts',
|
||||
output: {
|
||||
path: path.resolve(__dirname, './dist'),
|
||||
publicPath: '/dist/',
|
||||
filename: 'build.js'
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.vue$/,
|
||||
loader: 'vue-loader',
|
||||
options: {
|
||||
loaders: {
|
||||
// Since sass-loader (weirdly) has SCSS as its default parse mode, we map
|
||||
// the "scss" and "sass" values for the lang attribute to the right configs here.
|
||||
// other preprocessors should work out of the box, no loader config like this necessary.
|
||||
'scss': 'vue-style-loader!css-loader!sass-loader',
|
||||
'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax',
|
||||
}
|
||||
// other vue-loader options go here
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
loader: 'ts-loader',
|
||||
exclude: /node_modules/,
|
||||
options: {
|
||||
appendTsSuffixTo: [/\.vue$/],
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpg|gif|svg)$/,
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: '[name].[ext]?[hash]'
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
'style-loader',
|
||||
'css-loader'
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.ts', '.js', '.vue', '.json'],
|
||||
alias: {
|
||||
'vue$': 'vue/dist/vue.esm.js'
|
||||
}
|
||||
},
|
||||
devServer: {
|
||||
historyApiFallback: true,
|
||||
noInfo: true
|
||||
},
|
||||
performance: {
|
||||
hints: false
|
||||
},
|
||||
devtool: '#eval-source-map'
|
||||
}
|
Loading…
Reference in New Issue
Block a user