mirror of
https://github.com/Findus23/cr-search.git
synced 2024-09-19 15:23:44 +02:00
add transcript page
This commit is contained in:
parent
a06301b8a9
commit
3a829d74f9
7 changed files with 139 additions and 31 deletions
|
@ -48,11 +48,13 @@ body {
|
|||
border: 1px dashed $border-color;
|
||||
transition: background-color .2s;
|
||||
border-radius: 0;
|
||||
|
||||
&:focus, &:active {
|
||||
background: transparent;
|
||||
color: $body-color;
|
||||
}
|
||||
&:hover{
|
||||
|
||||
&:hover {
|
||||
background: rgba(177, 148, 54, 0.11);
|
||||
}
|
||||
}
|
||||
|
@ -70,18 +72,6 @@ body {
|
|||
|
||||
|
||||
.entry {
|
||||
.person {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.line {
|
||||
padding-left: 5px;
|
||||
border-left: solid 5px $background-color;
|
||||
|
||||
&.note, &.meta {
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: .529cm;
|
||||
|
@ -101,6 +91,24 @@ body {
|
|||
}
|
||||
}
|
||||
|
||||
.person {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.line {
|
||||
padding-left: 5px;
|
||||
border-left: solid 5px $background-color;
|
||||
|
||||
&.note, &.meta {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
&.highlighted {
|
||||
border: solid 5px $primary;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
p {
|
||||
font-family: "Bookinsanity", serif;
|
||||
}
|
||||
|
@ -114,9 +122,11 @@ footer {
|
|||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
|
||||
> * {
|
||||
padding: .5rem;
|
||||
}
|
||||
|
||||
button.btn-link {
|
||||
padding: 0;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,11 @@ export interface SeriesData extends Series {
|
|||
"length": number;
|
||||
}
|
||||
|
||||
export interface TranscriptData {
|
||||
episode: Episode;
|
||||
lines: Line[];
|
||||
}
|
||||
|
||||
export interface Episode {
|
||||
"episode_number": number;
|
||||
"id": number;
|
||||
|
|
|
@ -2,6 +2,7 @@ import Vue from "vue";
|
|||
import App from "./App.vue";
|
||||
import router from "./router";
|
||||
import "./custom.scss";
|
||||
import {VBTooltipPlugin} from "bootstrap-vue";
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
|
@ -10,3 +11,4 @@ new Vue({
|
|||
render: (h) => h(App),
|
||||
}).$mount("#app");
|
||||
|
||||
Vue.use(VBTooltipPlugin);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import Vue from "vue";
|
||||
import Router from "vue-router";
|
||||
import Home from "./views/Home.vue";
|
||||
import Episodes from "@/views/Episodes.vue";
|
||||
import Transcript from "@/views/Transcript.vue";
|
||||
|
||||
Vue.use(Router);
|
||||
|
||||
|
@ -12,11 +12,18 @@ export default new Router({
|
|||
{
|
||||
path: "/",
|
||||
redirect: "/campaign2/10/",
|
||||
name: "home"
|
||||
},
|
||||
{
|
||||
path: "/episodes",
|
||||
name: "episodes",
|
||||
component: () => import(/* webpackChunkName: "episodes" */ "./views/Episodes.vue"),
|
||||
component: () => import(/* webpackChunkName: "episodes" */ "./views/Episodes.vue"),
|
||||
},
|
||||
{
|
||||
path: "/transcript/:series/:episodeNr",
|
||||
name: "transcript",
|
||||
component: Transcript,
|
||||
props: true,
|
||||
},
|
||||
{
|
||||
path: "/:something/",
|
||||
|
@ -28,13 +35,5 @@ export default new Router({
|
|||
component: Home,
|
||||
// props: true,
|
||||
},
|
||||
// {
|
||||
// path: "/about",
|
||||
// name: "about",
|
||||
// // route level code-splitting
|
||||
// // this generates a separate chunk (about.[hash].js) for this route
|
||||
// // which is lazy-loaded when the route is visited.
|
||||
// component: () => import(/* webpackChunkName: "about" */ "./views/About.vue"),
|
||||
// },
|
||||
],
|
||||
});
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
<template>
|
||||
<div id="contentwrapper" class="text-page">
|
||||
<h1>Episode Overview</h1>
|
||||
<!-- <div v-for="series in series_data">-->
|
||||
<!-- <a :href="seriesID(series.meta,true)">{{ series.meta.title }}</a>-->
|
||||
<!-- </div>-->
|
||||
|
||||
|
||||
<div v-for="series in series_data" :key="series.meta.id" class="episode-table">
|
||||
<h2 :id="seriesID(series.meta)">{{ series.meta.title }}</h2>
|
||||
<table>
|
||||
|
|
|
@ -59,10 +59,18 @@
|
|||
<div class="title">
|
||||
<div>{{ formatTimestamp(firstLine(result).starttime) }} {{ episodeName(firstLine(result)) }}</div>
|
||||
<div class="buttons">
|
||||
<button class="btn" @click="playVideo(result)" title="View video on YouTube">
|
||||
<router-link :to="transcriptLink(result)" class="btn" target="_blank" v-b-tooltip
|
||||
title="Open this line in Transcript">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
|
||||
class="bi bi-blockquote-left" viewBox="0 0 16 16">
|
||||
<path d="M2.5 3a.5.5 0 0 0 0 1h11a.5.5 0 0 0 0-1h-11zm5 3a.5.5 0 0 0 0 1h6a.5.5 0 0 0 0-1h-6zm0 3a.5.5 0 0 0 0 1h6a.5.5 0 0 0 0-1h-6zm-5 3a.5.5 0 0 0 0 1h11a.5.5 0 0 0 0-1h-11zm.79-5.373c.112-.078.26-.17.444-.275L3.524 6c-.122.074-.272.17-.452.287-.18.117-.35.26-.51.428a2.425 2.425 0 0 0-.398.562c-.11.207-.164.438-.164.692 0 .36.072.65.217.873.144.219.385.328.72.328.215 0 .383-.07.504-.211a.697.697 0 0 0 .188-.463c0-.23-.07-.404-.211-.521-.137-.121-.326-.182-.568-.182h-.282c.024-.203.065-.37.123-.498a1.38 1.38 0 0 1 .252-.37 1.94 1.94 0 0 1 .346-.298zm2.167 0c.113-.078.262-.17.445-.275L5.692 6c-.122.074-.272.17-.452.287-.18.117-.35.26-.51.428a2.425 2.425 0 0 0-.398.562c-.11.207-.164.438-.164.692 0 .36.072.65.217.873.144.219.385.328.72.328.215 0 .383-.07.504-.211a.697.697 0 0 0 .188-.463c0-.23-.07-.404-.211-.521-.137-.121-.326-.182-.568-.182h-.282a1.75 1.75 0 0 1 .118-.492c.058-.13.144-.254.257-.375a1.94 1.94 0 0 1 .346-.3z"/>
|
||||
</svg>
|
||||
</router-link>
|
||||
<button class="btn" @click="playVideo(result)" title="Watch line on YouTube" v-b-tooltip>
|
||||
<b-icon-play-fill></b-icon-play-fill>
|
||||
</button>
|
||||
<button class="btn" v-if="result.offset<10" @click="expand(result)" title="Load more context">
|
||||
<button class="btn" v-if="result.offset<10" @click="expand(result)" title="Load more context"
|
||||
v-b-tooltip>
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
|
@ -98,7 +106,7 @@ import {BAlert, BIcon, BIconPlayFill} from "bootstrap-vue";
|
|||
// @ts-ignore
|
||||
import VueYoutube from "vue-youtube";
|
||||
import debounce from "lodash-es/debounce";
|
||||
|
||||
import {Location} from "vue-router";
|
||||
import {baseURL} from "@/utils";
|
||||
import SeriesSelector from "@/components/SeriesSelector.vue";
|
||||
import Intro from "@/components/Intro.vue";
|
||||
|
@ -344,6 +352,18 @@ export default Vue.extend({
|
|||
this.placeholderText = this.placeholderText.slice(0, -1);
|
||||
const offset = Math.random() * 40 - 20;
|
||||
this.placeholderTimeout = setTimeout(this.untype, 35 + offset);
|
||||
},
|
||||
transcriptLink(result: Result): Location {
|
||||
const firstline = this.firstLine(result);
|
||||
const episode = firstline.episode;
|
||||
return {
|
||||
name: "transcript",
|
||||
params: {
|
||||
episodeNr: episode.episode_number.toString(),
|
||||
series: episode.series.slug
|
||||
},
|
||||
hash: "#" + firstline.starttime
|
||||
};
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
|
77
web/src/views/Transcript.vue
Normal file
77
web/src/views/Transcript.vue
Normal file
|
@ -0,0 +1,77 @@
|
|||
<template>
|
||||
<div id="contentwrapper" class="text-page">
|
||||
<h1>{{ episode.pretty_title }}</h1>
|
||||
<p>
|
||||
<router-link :to="{name:'home'}">Back to the Homepage</router-link>
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
<strong>Note:</strong> This transcript-view is a work in progress and currently only shows very basic data.
|
||||
One day it might allow to jump to the position of a line in the Youtube video like on the main page.
|
||||
</blockquote>
|
||||
|
||||
<p :class="{line:true,note:line.isnote,meta:line.ismeta,highlighted:$route.hash.slice(1)===line.starttime.toString()}"
|
||||
:style="{borderLeftColor:getColor(line)}"
|
||||
v-for="line in lines" :key="line.id" :id="line.starttime">
|
||||
<span v-if="line.person" class="person">{{ line.person.name }}: </span><span
|
||||
v-html="line.text"></span>
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import {Episode, Line, TranscriptData} from "@/interfaces";
|
||||
import {baseURL} from "@/utils";
|
||||
import CheckMark from "@/components/CheckMark.vue";
|
||||
|
||||
export default Vue.extend({
|
||||
name: "Transcript",
|
||||
props: {
|
||||
episodeNr: String,
|
||||
series: String
|
||||
},
|
||||
components: {
|
||||
CheckMark
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
lines: [] as Line[],
|
||||
episode: {} as Episode,
|
||||
loaded: false
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
console.log(this.episodeNr);
|
||||
fetch(baseURL + "transcript?episode=" + this.episodeNr + "&series=" + this.series)
|
||||
.then((response) => response.json())
|
||||
.then((data: TranscriptData) => {
|
||||
this.episode = data.episode;
|
||||
this.lines = data.lines;
|
||||
this.loaded = true;
|
||||
const hash = this.$route.hash;
|
||||
if (hash) {
|
||||
Vue.nextTick(function() {
|
||||
document.getElementById(hash.slice(1))?.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
getColor(line: Line): string {
|
||||
if (line.ismeta) {
|
||||
return "pink";
|
||||
} else if (line.isnote) {
|
||||
return "purple";
|
||||
}
|
||||
if (line.person) {
|
||||
return line.person.color;
|
||||
}
|
||||
return "white";
|
||||
},
|
||||
|
||||
}
|
||||
});
|
||||
</script>
|
Loading…
Reference in a new issue