Compare commits
9 Commits
1e1938e7f8
...
ca901c91c5
Author | SHA1 | Date |
---|---|---|
Alex Kotov | ca901c91c5 | |
Chocobozzz | 0c302acb3c | |
Chocobozzz | 995599654e | |
Chocobozzz | 80a94b04fb | |
Chocobozzz | ed22eaabfa | |
Chocobozzz | d98909f690 | |
Chocobozzz | ae22c59f14 | |
Chocobozzz | ba278fa51d | |
Chocobozzz | 2c16f5ad5e |
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -1,5 +1,15 @@
|
|||
# Changelog
|
||||
|
||||
## v5.2.1
|
||||
|
||||
### Bug fixes
|
||||
|
||||
* Fix loading spinner displayed forever on Chrome
|
||||
* Fix broken replay with long live name
|
||||
* Fix fps transcoding on remote runners
|
||||
* Fix terms/code of conduct link toggle
|
||||
|
||||
|
||||
## v5.2.0
|
||||
|
||||
### IMPORTANT NOTES
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "peertube-client",
|
||||
"version": "5.2.0",
|
||||
"version": "5.2.1",
|
||||
"private": true,
|
||||
"license": "AGPL-3.0",
|
||||
"author": {
|
||||
|
|
|
@ -105,6 +105,7 @@
|
|||
|
||||
<div #instanceInformation class="instance-information">
|
||||
<my-instance-about-accordion
|
||||
#instanceAboutAccordion
|
||||
[displayInstanceName]="false"
|
||||
(init)="onInstanceAboutAccordionInit($event)" [panels]="instanceInformationPanels"
|
||||
pluginScope="login" pluginHook="filter:login.instance-about-plugin-panels.create.result"
|
||||
|
|
|
@ -22,6 +22,7 @@ export class LoginComponent extends FormReactive implements OnInit, AfterViewIni
|
|||
|
||||
@ViewChild('forgotPasswordModal', { static: true }) forgotPasswordModal: ElementRef
|
||||
@ViewChild('otpTokenInput') otpTokenInput: InputTextComponent
|
||||
@ViewChild('instanceAboutAccordion') instanceAboutAccordion: InstanceAboutAccordionComponent
|
||||
|
||||
accordion: NgbAccordionDirective
|
||||
error: string = null
|
||||
|
@ -70,8 +71,8 @@ export class LoginComponent extends FormReactive implements OnInit, AfterViewIni
|
|||
onTermsClick (event: Event, instanceInformation: HTMLElement) {
|
||||
event.preventDefault()
|
||||
|
||||
if (this.accordion) {
|
||||
this.accordion.expand('terms')
|
||||
if (this.instanceAboutAccordion) {
|
||||
this.instanceAboutAccordion.expandTerms()
|
||||
instanceInformation.scrollIntoView({ behavior: 'smooth' })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
</my-signup-step-title>
|
||||
|
||||
<my-instance-about-accordion
|
||||
#instanceAboutAccordion
|
||||
[displayInstanceName]="false"
|
||||
(init)="onInstanceAboutAccordionInit($event)" [panels]="instanceInformationPanels"
|
||||
pluginScope="signup" pluginHook="filter:signup.instance-about-plugin-panels.create.result"
|
||||
|
|
|
@ -5,7 +5,6 @@ import { ActivatedRoute } from '@angular/router'
|
|||
import { AuthService } from '@app/core'
|
||||
import { HooksService } from '@app/core/plugins/hooks.service'
|
||||
import { InstanceAboutAccordionComponent } from '@app/shared/shared-instance'
|
||||
import { NgbAccordionDirective } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { UserRegister } from '@shared/models'
|
||||
import { ServerConfig } from '@shared/models/server'
|
||||
import { SignupService } from '../shared/signup.service'
|
||||
|
@ -17,8 +16,7 @@ import { SignupService } from '../shared/signup.service'
|
|||
})
|
||||
export class RegisterComponent implements OnInit {
|
||||
@ViewChild('lastStep') lastStep: CdkStep
|
||||
|
||||
accordion: NgbAccordionDirective
|
||||
@ViewChild('instanceAboutAccordion') instanceAboutAccordion: InstanceAboutAccordionComponent
|
||||
|
||||
signupError: string
|
||||
signupSuccess = false
|
||||
|
@ -121,15 +119,14 @@ export class RegisterComponent implements OnInit {
|
|||
}
|
||||
|
||||
onTermsClick () {
|
||||
if (this.accordion) this.accordion.toggle('terms')
|
||||
this.instanceAboutAccordion.expandTerms()
|
||||
}
|
||||
|
||||
onCodeOfConductClick () {
|
||||
if (this.accordion) this.accordion.toggle('code-of-conduct')
|
||||
this.instanceAboutAccordion.expandCodeOfConduct()
|
||||
}
|
||||
|
||||
onInstanceAboutAccordionInit (instanceAboutAccordion: InstanceAboutAccordionComponent) {
|
||||
this.accordion = instanceAboutAccordion.accordion
|
||||
this.aboutHtml = instanceAboutAccordion.aboutHtml
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<div *ngIf="displayInstanceShortDescription" class="instance-short-description ellipsis-multiline-3">{{ about?.instance.shortDescription }}</div>
|
||||
|
||||
<div ngbAccordion #accordion="ngbAccordion" [closeOthers]="true">
|
||||
<div ngbAccordionItem *ngIf="panels.features" id="instance-features">
|
||||
<div ngbAccordionItem="instance-features" *ngIf="panels.features">
|
||||
<div ngbAccordionHeader>
|
||||
<button ngbAccordionButton>
|
||||
<my-global-icon iconName="playlists"></my-global-icon>
|
||||
|
@ -53,7 +53,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div ngbAccordionItem *ngIf="termsPanel" id="terms">
|
||||
<div ngbAccordionItem="terms" *ngIf="termsPanel">
|
||||
<div ngbAccordionHeader>
|
||||
<button ngbAccordionButton>
|
||||
<my-global-icon iconName="playlists"></my-global-icon>
|
||||
|
@ -71,7 +71,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div ngbAccordionItem *ngIf="moderationPanel" id="moderation-information">
|
||||
<div ngbAccordionItem="moderation-information" *ngIf="moderationPanel">
|
||||
<div ngbAccordionHeader>
|
||||
<button ngbAccordionButton>
|
||||
<my-global-icon iconName="playlists"></my-global-icon>
|
||||
|
@ -89,7 +89,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div ngbAccordionItem *ngIf="codeOfConductPanel" id="code-of-conduct">
|
||||
<div ngbAccordionItem="code-of-conduct" *ngIf="codeOfConductPanel">
|
||||
<div ngbAccordionHeader>
|
||||
<button ngbAccordionButton>
|
||||
<my-global-icon iconName="playlists"></my-global-icon>
|
||||
|
|
|
@ -62,6 +62,14 @@ export class InstanceAboutAccordionComponent implements OnInit {
|
|||
this.pluginPanels = await this.hookService.wrapObject([], this.pluginScope, this.pluginHook)
|
||||
}
|
||||
|
||||
expandTerms () {
|
||||
this.accordion.expand('terms')
|
||||
}
|
||||
|
||||
expandCodeOfConduct () {
|
||||
this.accordion.expand('code-of-conduct')
|
||||
}
|
||||
|
||||
getAdministratorsPanel () {
|
||||
if (!this.about) return false
|
||||
if (!this.panels.administrators) return false
|
||||
|
|
|
@ -35,18 +35,15 @@
|
|||
|
||||
@keyframes vjs-spinner-show {
|
||||
0% {
|
||||
display: none;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
1% {
|
||||
display: block;
|
||||
visibility: visible;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
display: block;
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "peertube",
|
||||
"description": "PeerTube, an ActivityPub-federated video streaming platform using P2P directly in your web browser.",
|
||||
"version": "5.2.0",
|
||||
"version": "5.2.1",
|
||||
"private": true,
|
||||
"licence": "AGPL-3.0",
|
||||
"engines": {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import express from 'express'
|
||||
import { maxBy } from 'lodash'
|
||||
import { Feed } from '@peertube/feed'
|
||||
import { CustomTag, CustomXMLNS, Person } from '@peertube/feed/lib/typings'
|
||||
import { mdToOneLinePlainText } from '@server/helpers/markdown'
|
||||
import { CONFIG } from '@server/initializers/config'
|
||||
import { WEBSERVER } from '@server/initializers/constants'
|
||||
import { getBiggestActorImage } from '@server/lib/actor-image'
|
||||
import { UserModel } from '@server/models/user/user'
|
||||
import { MAccountDefault, MChannelBannerAccountDefault, MUser, MVideoFullLight } from '@server/types/models'
|
||||
import { pick } from '@shared/core-utils'
|
||||
|
@ -105,12 +105,12 @@ export async function buildFeedMetadata (options: {
|
|||
accountLink = videoChannel.Account.getClientUrl()
|
||||
|
||||
if (videoChannel.Actor.hasImage(ActorImageType.AVATAR)) {
|
||||
const videoChannelAvatar = maxBy(videoChannel.Actor.Avatars, 'width')
|
||||
const videoChannelAvatar = getBiggestActorImage(videoChannel.Actor.Avatars)
|
||||
imageUrl = WEBSERVER.URL + videoChannelAvatar.getStaticPath()
|
||||
}
|
||||
|
||||
if (videoChannel.Account.Actor.hasImage(ActorImageType.AVATAR)) {
|
||||
const accountAvatar = maxBy(videoChannel.Account.Actor.Avatars, 'width')
|
||||
const accountAvatar = getBiggestActorImage(videoChannel.Account.Actor.Avatars)
|
||||
accountImageUrl = WEBSERVER.URL + accountAvatar.getStaticPath()
|
||||
}
|
||||
|
||||
|
@ -123,7 +123,7 @@ export async function buildFeedMetadata (options: {
|
|||
accountLink = link
|
||||
|
||||
if (account.Actor.hasImage(ActorImageType.AVATAR)) {
|
||||
const accountAvatar = maxBy(account.Actor.Avatars, 'width')
|
||||
const accountAvatar = getBiggestActorImage(account.Actor.Avatars)
|
||||
imageUrl = WEBSERVER.URL + accountAvatar?.getStaticPath()
|
||||
accountImageUrl = imageUrl
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import express from 'express'
|
||||
import { maxBy } from 'lodash'
|
||||
import { extname } from 'path'
|
||||
import { Feed } from '@peertube/feed'
|
||||
import { CustomTag, CustomXMLNS, LiveItemStatus } from '@peertube/feed/lib/typings'
|
||||
import { getBiggestActorImage } from '@server/lib/actor-image'
|
||||
import { InternalEventEmitter } from '@server/lib/internal-event-emitter'
|
||||
import { Hooks } from '@server/lib/plugins/hooks'
|
||||
import { buildPodcastGroupsCache, cacheRouteFactory, videoFeedsPodcastSetCacheKey } from '@server/middlewares'
|
||||
|
@ -150,7 +150,7 @@ async function generatePodcastItem (options: {
|
|||
let personImage: string
|
||||
|
||||
if (account.Actor.hasImage(ActorImageType.AVATAR)) {
|
||||
const avatar = maxBy(account.Actor.Avatars, 'width')
|
||||
const avatar = getBiggestActorImage(account.Actor.Avatars)
|
||||
personImage = WEBSERVER.URL + avatar.getStaticPath()
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@ import { MVideo, MVideoLive, MVideoLiveSession, MVideoWithAllFiles } from '@serv
|
|||
import { ffprobePromise, getAudioStream, getVideoStreamDimensionsInfo, getVideoStreamFPS } from '@shared/ffmpeg'
|
||||
import { ThumbnailType, VideoLiveEndingPayload, VideoState } from '@shared/models'
|
||||
import { logger, loggerTagsFactory } from '../../../helpers/logger'
|
||||
import { peertubeTruncate } from '@server/helpers/core-utils'
|
||||
import { CONSTRAINTS_FIELDS } from '@server/initializers/constants'
|
||||
|
||||
const lTags = loggerTagsFactory('live', 'job')
|
||||
|
||||
|
@ -88,8 +90,13 @@ async function saveReplayToExternalVideo (options: {
|
|||
|
||||
const replaySettings = await VideoLiveReplaySettingModel.load(liveSession.replaySettingId)
|
||||
|
||||
const videoNameSuffix = ` - ${new Date(publishedAt).toLocaleString()}`
|
||||
const truncatedVideoName = peertubeTruncate(liveVideo.name, {
|
||||
length: CONSTRAINTS_FIELDS.VIDEOS.NAME.max - videoNameSuffix.length
|
||||
})
|
||||
|
||||
const replayVideo = new VideoModel({
|
||||
name: `${liveVideo.name} - ${new Date(publishedAt).toLocaleString()}`,
|
||||
name: truncatedVideoName + videoNameSuffix,
|
||||
isLive: false,
|
||||
state: VideoState.TO_TRANSCODE,
|
||||
duration: 0,
|
||||
|
|
|
@ -115,7 +115,7 @@ export class TranscodingRunnerJobBuilder extends AbstractJobBuilder {
|
|||
|
||||
for (const resolution of childrenResolutions) {
|
||||
const dependsOnRunnerJob = mainJob
|
||||
const fps = computeOutputFPS({ inputFPS, resolution: maxResolution })
|
||||
const fps = computeOutputFPS({ inputFPS, resolution })
|
||||
|
||||
if (transcodingType === 'hls') {
|
||||
await new VODHLSTranscodingJobHandler().create({
|
||||
|
|
|
@ -38,7 +38,7 @@ describe('Save replay setting', function () {
|
|||
const attributes: LiveVideoCreate = {
|
||||
channelId: servers[0].store.channel.id,
|
||||
privacy: VideoPrivacy.PUBLIC,
|
||||
name: 'my super live',
|
||||
name: 'live'.repeat(30),
|
||||
saveReplay: options.replay,
|
||||
replaySettings: options.replaySettings,
|
||||
permanentLive: options.permanent
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import ffmpeg, { FfmpegCommand } from 'fluent-ffmpeg'
|
||||
import { truncate } from 'lodash'
|
||||
import { buildAbsoluteFixturePath, wait } from '@shared/core-utils'
|
||||
import { VideoDetails, VideoInclude, VideoPrivacy } from '@shared/models'
|
||||
import { PeerTubeServer } from '../server/server'
|
||||
|
@ -104,7 +105,13 @@ async function findExternalSavedVideo (server: PeerTubeServer, liveDetails: Vide
|
|||
|
||||
const { data } = await server.videos.list({ token: server.accessToken, sort: '-publishedAt', include, privacyOneOf })
|
||||
|
||||
return data.find(v => v.name === liveDetails.name + ' - ' + new Date(liveDetails.publishedAt).toLocaleString())
|
||||
const videoNameSuffix = ` - ${new Date(liveDetails.publishedAt).toLocaleString()}`
|
||||
const truncatedVideoName = truncate(liveDetails.name, {
|
||||
length: 120 - videoNameSuffix.length
|
||||
})
|
||||
const toFind = truncatedVideoName + videoNameSuffix
|
||||
|
||||
return data.find(v => v.name === toFind)
|
||||
}
|
||||
|
||||
export {
|
||||
|
|
Loading…
Reference in New Issue