Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
7
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Open sidebar
Framasoft
PeerTube
PeerTube
Commits
84531547
Verified
Commit
84531547
authored
Apr 08, 2021
by
Chocobozzz
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add size info in db for actor images
parent
a0eeb45f
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
126 additions
and
48 deletions
+126
-48
scripts/regenerate-thumbnails.ts
scripts/regenerate-thumbnails.ts
+2
-3
server/helpers/image-utils.ts
server/helpers/image-utils.ts
+6
-0
server/initializers/constants.ts
server/initializers/constants.ts
+1
-1
server/initializers/migrations/0635-actor-image-size.ts
server/initializers/migrations/0635-actor-image-size.ts
+35
-0
server/lib/activitypub/actor.ts
server/lib/activitypub/actor.ts
+25
-10
server/lib/activitypub/videos.ts
server/lib/activitypub/videos.ts
+16
-22
server/lib/actor-image.ts
server/lib/actor-image.ts
+2
-0
server/lib/thumbnail.ts
server/lib/thumbnail.ts
+5
-5
server/models/account/actor-image.ts
server/models/account/actor-image.ts
+11
-6
server/models/activitypub/actor.ts
server/models/activitypub/actor.ts
+6
-1
server/tests/api/videos/video-channels.ts
server/tests/api/videos/video-channels.ts
+11
-0
shared/extra-utils/miscs/sql.ts
shared/extra-utils/miscs/sql.ts
+6
-0
No files found.
scripts/regenerate-thumbnails.ts
View file @
84531547
...
...
@@ -4,12 +4,11 @@ registerTSPaths()
import
*
as
Bluebird
from
'
bluebird
'
import
*
as
program
from
'
commander
'
import
{
pathExists
,
remove
}
from
'
fs-extra
'
import
{
processImage
}
from
'
@server/helpers/image-utils
'
import
{
generateImageFilename
,
processImage
}
from
'
@server/helpers/image-utils
'
import
{
THUMBNAILS_SIZE
}
from
'
@server/initializers/constants
'
import
{
VideoModel
}
from
'
@server/models/video/video
'
import
{
MVideo
}
from
'
@server/types/models
'
import
{
initDatabaseModels
}
from
'
@server/initializers/database
'
import
{
ActorImageModel
}
from
'
@server/models/account/actor-image
'
program
.
description
(
'
Regenerate local thumbnails using preview files
'
)
...
...
@@ -52,7 +51,7 @@ async function processVideo (videoArg: MVideo) {
const
oldPath
=
thumbnail
.
getPath
()
// Update thumbnail
thumbnail
.
filename
=
ActorImageModel
.
generateFilename
()
thumbnail
.
filename
=
generate
Image
Filename
()
thumbnail
.
width
=
size
.
width
thumbnail
.
height
=
size
.
height
...
...
server/helpers/image-utils.ts
View file @
84531547
import
{
copy
,
readFile
,
remove
,
rename
}
from
'
fs-extra
'
import
*
as
Jimp
from
'
jimp
'
import
{
extname
}
from
'
path
'
import
{
v4
as
uuidv4
}
from
'
uuid
'
import
{
convertWebPToJPG
,
processGIF
}
from
'
./ffmpeg-utils
'
import
{
logger
}
from
'
./logger
'
function
generateImageFilename
(
extension
=
'
.jpg
'
)
{
return
uuidv4
()
+
extension
}
async
function
processImage
(
path
:
string
,
destination
:
string
,
...
...
@@ -31,6 +36,7 @@ async function processImage (
// ---------------------------------------------------------------------------
export
{
generateImageFilename
,
processImage
}
...
...
server/initializers/constants.ts
View file @
84531547
...
...
@@ -24,7 +24,7 @@ import { CONFIG, registerConfigChangedHandler } from './config'
// ---------------------------------------------------------------------------
const
LAST_MIGRATION_VERSION
=
63
0
const
LAST_MIGRATION_VERSION
=
63
5
// ---------------------------------------------------------------------------
...
...
server/initializers/migrations/0635-actor-image-size.ts
0 → 100644
View file @
84531547
import
*
as
Sequelize
from
'
sequelize
'
async
function
up
(
utils
:
{
transaction
:
Sequelize
.
Transaction
queryInterface
:
Sequelize
.
QueryInterface
sequelize
:
Sequelize
.
Sequelize
db
:
any
}):
Promise
<
void
>
{
{
const
data
=
{
type
:
Sequelize
.
INTEGER
,
defaultValue
:
null
,
allowNull
:
true
}
await
utils
.
queryInterface
.
addColumn
(
'
actorImage
'
,
'
height
'
,
data
)
}
{
const
data
=
{
type
:
Sequelize
.
INTEGER
,
defaultValue
:
null
,
allowNull
:
true
}
await
utils
.
queryInterface
.
addColumn
(
'
actorImage
'
,
'
width
'
,
data
)
}
}
function
down
(
options
)
{
throw
new
Error
(
'
Not implemented.
'
)
}
export
{
up
,
down
}
server/lib/activitypub/actor.ts
View file @
84531547
...
...
@@ -170,7 +170,13 @@ async function updateActorInstance (actorInstance: ActorModel, attributes: Activ
}
}
type
ImageInfo
=
{
name
:
string
,
onDisk
?:
boolean
,
fileUrl
:
string
}
type
ImageInfo
=
{
name
:
string
fileUrl
:
string
height
:
number
width
:
number
onDisk
?:
boolean
}
async
function
updateActorImageInstance
(
actor
:
MActorImages
,
type
:
ActorImageType
,
imageInfo
:
ImageInfo
|
null
,
t
:
Transaction
)
{
const
oldImageModel
=
type
===
ActorImageType
.
AVATAR
?
actor
.
Avatar
...
...
@@ -194,7 +200,9 @@ async function updateActorImageInstance (actor: MActorImages, type: ActorImageTy
filename
:
imageInfo
.
name
,
onDisk
:
imageInfo
.
onDisk
??
false
,
fileUrl
:
imageInfo
.
fileUrl
,
type
:
type
height
:
imageInfo
.
height
,
width
:
imageInfo
.
width
,
type
},
{
transaction
:
t
})
setActorImage
(
actor
,
type
,
imageModel
)
...
...
@@ -257,6 +265,8 @@ function getImageInfoIfExists (actorJSON: ActivityPubActor, type: ActorImageType
return
{
name
:
uuidv4
()
+
extension
,
fileUrl
:
icon
.
url
,
height
:
icon
.
height
,
width
:
icon
.
width
,
type
}
}
...
...
@@ -408,6 +418,8 @@ function saveActorAndServerAndModelIfNotExist (
const
avatar
=
await
ActorImageModel
.
create
({
filename
:
result
.
avatar
.
name
,
fileUrl
:
result
.
avatar
.
fileUrl
,
width
:
result
.
avatar
.
width
,
height
:
result
.
avatar
.
height
,
onDisk
:
false
,
type
:
ActorImageType
.
AVATAR
},
{
transaction
:
t
})
...
...
@@ -420,6 +432,8 @@ function saveActorAndServerAndModelIfNotExist (
const
banner
=
await
ActorImageModel
.
create
({
filename
:
result
.
banner
.
name
,
fileUrl
:
result
.
banner
.
fileUrl
,
width
:
result
.
banner
.
width
,
height
:
result
.
banner
.
height
,
onDisk
:
false
,
type
:
ActorImageType
.
BANNER
},
{
transaction
:
t
})
...
...
@@ -470,20 +484,21 @@ function saveActorAndServerAndModelIfNotExist (
}
}
type
ImageResult
=
{
name
:
string
fileUrl
:
string
height
:
number
width
:
number
}
type
FetchRemoteActorResult
=
{
actor
:
MActor
name
:
string
summary
:
string
support
?:
string
playlists
?:
string
avatar
?:
{
name
:
string
fileUrl
:
string
}
banner
?:
{
name
:
string
fileUrl
:
string
}
avatar
?:
ImageResult
banner
?:
ImageResult
attributedTo
:
ActivityPubAttributedTo
[]
}
async
function
fetchRemoteActor
(
actorUrl
:
string
):
Promise
<
{
statusCode
?:
number
,
result
:
FetchRemoteActorResult
}
>
{
...
...
server/lib/activitypub/videos.ts
View file @
84531547
import
*
as
Bluebird
from
'
bluebird
'
import
{
maxBy
,
minBy
}
from
'
lodash
'
import
*
as
magnetUtil
from
'
magnet-uri
'
import
{
basename
,
join
}
from
'
path
'
import
{
basename
}
from
'
path
'
import
{
Transaction
}
from
'
sequelize/types
'
import
{
ActorImageModel
}
from
'
@server/models/account/actor-image
'
import
{
TrackerModel
}
from
'
@server/models/server/tracker
'
import
{
VideoLiveModel
}
from
'
@server/models/video/video-live
'
import
{
HttpStatusCode
}
from
'
../../../shared/core-utils/miscs/http-error-codes
'
...
...
@@ -17,7 +16,7 @@ import {
ActivityUrlObject
,
ActivityVideoUrlObject
}
from
'
../../../shared/index
'
import
{
ActivityIconObject
,
ActivityTrackerUrlObject
,
VideoObject
}
from
'
../../../shared/models/activitypub/objects
'
import
{
ActivityTrackerUrlObject
,
VideoObject
}
from
'
../../../shared/models/activitypub/objects
'
import
{
VideoPrivacy
}
from
'
../../../shared/models/videos
'
import
{
ThumbnailType
}
from
'
../../../shared/models/videos/thumbnail.type
'
import
{
VideoStreamingPlaylistType
}
from
'
../../../shared/models/videos/video-streaming-playlist.type
'
...
...
@@ -35,7 +34,6 @@ import { doJSONRequest, PeerTubeRequestError } from '../../helpers/requests'
import
{
fetchVideoByUrl
,
getExtFromMimetype
,
VideoFetchByUrlType
}
from
'
../../helpers/video
'
import
{
ACTIVITY_PUB
,
LAZY_STATIC_PATHS
,
MIMETYPES
,
P2P_MEDIA_LOADER_PEER_VERSION
,
PREVIEWS_SIZE
,
...
...
@@ -368,13 +366,13 @@ async function updateVideoFromAP (options: {
if
(
thumbnailModel
)
await
videoUpdated
.
addAndSaveThumbnail
(
thumbnailModel
,
t
)
if
(
videoUpdated
.
getPreview
())
{
const
previewUrl
=
getPreviewUrl
(
getPreviewFromIcons
(
videoObject
),
video
)
const
previewIcon
=
getPreviewFromIcons
(
videoObject
)
if
(
videoUpdated
.
getPreview
()
&&
previewIcon
)
{
const
previewModel
=
createPlaceholderThumbnail
({
fileUrl
:
preview
U
rl
,
fileUrl
:
preview
Icon
.
u
rl
,
video
,
type
:
ThumbnailType
.
PREVIEW
,
size
:
PREVIEWS_SIZE
size
:
previewIcon
})
await
videoUpdated
.
addAndSaveThumbnail
(
previewModel
,
t
)
}
...
...
@@ -629,15 +627,17 @@ async function createVideo (videoObject: VideoObject, channel: MChannelAccountLi
if
(
thumbnailModel
)
await
videoCreated
.
addAndSaveThumbnail
(
thumbnailModel
,
t
)
const
previewUrl
=
getPreviewUrl
(
getPreviewFromIcons
(
videoObject
),
videoCreated
)
const
previewModel
=
createPlaceholderThumbnail
({
fileUrl
:
previewUrl
,
video
:
videoCreated
,
type
:
ThumbnailType
.
PREVIEW
,
size
:
PREVIEWS_SIZE
})
const
previewIcon
=
getPreviewFromIcons
(
videoObject
)
if
(
previewIcon
)
{
const
previewModel
=
createPlaceholderThumbnail
({
fileUrl
:
previewIcon
.
url
,
video
:
videoCreated
,
type
:
ThumbnailType
.
PREVIEW
,
size
:
previewIcon
})
if
(
thumbnailModel
)
await
videoCreated
.
addAndSaveThumbnail
(
previewModel
,
t
)
await
videoCreated
.
addAndSaveThumbnail
(
previewModel
,
t
)
}
// Process files
const
videoFileAttributes
=
videoFileActivityUrlToDBAttributes
(
videoCreated
,
videoObject
.
url
)
...
...
@@ -897,12 +897,6 @@ function getPreviewFromIcons (videoObject: VideoObject) {
return
maxBy
(
validIcons
,
'
width
'
)
}
function
getPreviewUrl
(
previewIcon
:
ActivityIconObject
,
video
:
MVideoWithHost
)
{
return
previewIcon
?
previewIcon
.
url
:
buildRemoteVideoBaseUrl
(
video
,
join
(
LAZY_STATIC_PATHS
.
PREVIEWS
,
ActorImageModel
.
generateFilename
()))
}
function
getTrackerUrls
(
object
:
VideoObject
,
video
:
MVideoWithHost
)
{
let
wsFound
=
false
...
...
server/lib/actor-image.ts
View file @
84531547
...
...
@@ -34,6 +34,8 @@ async function updateLocalActorImageFile (
const
actorImageInfo
=
{
name
:
imageName
,
fileUrl
:
null
,
height
:
imageSize
.
height
,
width
:
imageSize
.
width
,
onDisk
:
true
}
...
...
server/lib/thumbnail.ts
View file @
84531547
import
{
join
}
from
'
path
'
import
{
ActorImageModel
}
from
'
@server/models/account/actor-image
'
import
{
ThumbnailType
}
from
'
../../shared/models/videos/thumbnail.type
'
import
{
generateImageFromVideoFile
}
from
'
../helpers/ffmpeg-utils
'
import
{
processImage
}
from
'
../helpers/image-utils
'
import
{
generateImageFilename
,
processImage
}
from
'
../helpers/image-utils
'
import
{
downloadImage
}
from
'
../helpers/requests
'
import
{
CONFIG
}
from
'
../initializers/config
'
import
{
ASSETS_PATH
,
PREVIEWS_SIZE
,
THUMBNAILS_SIZE
}
from
'
../initializers/constants
'
...
...
@@ -12,7 +12,7 @@ import { MThumbnail } from '../types/models/video/thumbnail'
import
{
MVideoPlaylistThumbnail
}
from
'
../types/models/video/video-playlist
'
import
{
getVideoFilePath
}
from
'
./video-paths
'
type
ImageSize
=
{
height
:
number
,
width
:
number
}
type
ImageSize
=
{
height
?
:
number
,
width
?
:
number
}
function
createPlaylistMiniatureFromExisting
(
options
:
{
inputPath
:
string
...
...
@@ -201,7 +201,7 @@ function buildMetadataFromVideo (video: MVideoThumbnail, type: ThumbnailType, si
:
undefined
if
(
type
===
ThumbnailType
.
MINIATURE
)
{
const
filename
=
ActorImageModel
.
generateFilename
()
const
filename
=
generate
Image
Filename
()
const
basePath
=
CONFIG
.
STORAGE
.
THUMBNAILS_DIR
return
{
...
...
@@ -215,7 +215,7 @@ function buildMetadataFromVideo (video: MVideoThumbnail, type: ThumbnailType, si
}
if
(
type
===
ThumbnailType
.
PREVIEW
)
{
const
filename
=
ActorImageModel
.
generateFilename
()
const
filename
=
generate
Image
Filename
()
const
basePath
=
CONFIG
.
STORAGE
.
PREVIEWS_DIR
return
{
...
...
server/models/account/actor-image.ts
View file @
84531547
import
{
remove
}
from
'
fs-extra
'
import
{
join
}
from
'
path
'
import
{
AfterDestroy
,
AllowNull
,
Column
,
CreatedAt
,
Is
,
Model
,
Table
,
UpdatedAt
}
from
'
sequelize-typescript
'
import
{
v4
as
uuidv4
}
from
'
uuid
'
import
{
AfterDestroy
,
AllowNull
,
Column
,
CreatedAt
,
Default
,
Is
,
Model
,
Table
,
UpdatedAt
}
from
'
sequelize-typescript
'
import
{
MActorImageFormattable
}
from
'
@server/types/models
'
import
{
ActorImageType
}
from
'
@shared/models
'
import
{
ActorImage
}
from
'
../../../shared/models/actors/actor-image.model
'
...
...
@@ -26,6 +25,16 @@ export class ActorImageModel extends Model {
@
Column
filename
:
string
@
AllowNull
(
true
)
@
Default
(
null
)
@
Column
height
:
number
@
AllowNull
(
true
)
@
Default
(
null
)
@
Column
width
:
number
@
AllowNull
(
true
)
@
Is
(
'
ActorImageFileUrl
'
,
value
=>
throwIfNotValid
(
value
,
isActivityPubUrlValid
,
'
fileUrl
'
,
true
))
@
Column
...
...
@@ -54,10 +63,6 @@ export class ActorImageModel extends Model {
.
catch
(
err
=>
logger
.
error
(
'
Cannot remove actor image file %s.
'
,
instance
.
filename
,
err
))
}
static
generateFilename
()
{
return
uuidv4
()
+
'
.jpg
'
}
static
loadByName
(
filename
:
string
)
{
const
query
=
{
where
:
{
...
...
server/models/activitypub/actor.ts
View file @
84531547
...
...
@@ -570,16 +570,21 @@ export class ActorModel extends Model {
icon
=
{
type
:
'
Image
'
,
mediaType
:
MIMETYPES
.
IMAGE
.
EXT_MIMETYPE
[
extension
],
height
:
this
.
Avatar
.
height
,
width
:
this
.
Avatar
.
width
,
url
:
this
.
getAvatarUrl
()
}
}
if
(
this
.
bannerId
)
{
const
extension
=
extname
((
this
as
MActorAPChannel
).
Banner
.
filename
)
const
banner
=
(
this
as
MActorAPChannel
).
Banner
const
extension
=
extname
(
banner
.
filename
)
image
=
{
type
:
'
Image
'
,
mediaType
:
MIMETYPES
.
IMAGE
.
EXT_MIMETYPE
[
extension
],
height
:
banner
.
height
,
width
:
banner
.
width
,
url
:
this
.
getBannerUrl
()
}
}
...
...
server/tests/api/videos/video-channels.ts
View file @
84531547
...
...
@@ -2,12 +2,14 @@
import
'
mocha
'
import
*
as
chai
from
'
chai
'
import
{
basename
}
from
'
path
'
import
{
cleanupTests
,
createUser
,
deleteVideoChannelImage
,
doubleFollow
,
flushAndRunMultipleServers
,
getActorImage
,
getVideo
,
getVideoChannel
,
getVideoChannelVideos
,
...
...
@@ -31,6 +33,7 @@ import {
}
from
'
../../../../shared/extra-utils/index
'
import
{
waitJobs
}
from
'
../../../../shared/extra-utils/server/jobs
'
import
{
User
,
Video
,
VideoChannel
,
VideoDetails
}
from
'
../../../../shared/index
'
import
{
ACTOR_IMAGES_SIZE
}
from
'
@server/initializers/constants
'
const
expect
=
chai
.
expect
...
...
@@ -288,6 +291,10 @@ describe('Test video channels', function () {
const
videoChannel
=
await
findChannel
(
server
,
secondVideoChannelId
)
await
testImage
(
server
.
url
,
'
avatar-resized
'
,
videoChannel
.
avatar
.
path
,
'
.png
'
)
const
row
=
await
getActorImage
(
server
.
internalServerNumber
,
basename
(
videoChannel
.
avatar
.
path
))
expect
(
row
.
height
).
to
.
equal
(
ACTOR_IMAGES_SIZE
.
AVATARS
.
height
)
expect
(
row
.
width
).
to
.
equal
(
ACTOR_IMAGES_SIZE
.
AVATARS
.
width
)
}
})
...
...
@@ -311,6 +318,10 @@ describe('Test video channels', function () {
const
videoChannel
=
res
.
body
await
testImage
(
server
.
url
,
'
banner-resized
'
,
videoChannel
.
banner
.
path
)
const
row
=
await
getActorImage
(
server
.
internalServerNumber
,
basename
(
videoChannel
.
banner
.
path
))
expect
(
row
.
height
).
to
.
equal
(
ACTOR_IMAGES_SIZE
.
BANNERS
.
height
)
expect
(
row
.
width
).
to
.
equal
(
ACTOR_IMAGES_SIZE
.
BANNERS
.
width
)
}
})
...
...
shared/extra-utils/miscs/sql.ts
View file @
84531547
...
...
@@ -82,6 +82,11 @@ async function countVideoViewsOf (internalServerNumber: number, uuid: string) {
return
parseInt
(
total
+
''
,
10
)
}
function
getActorImage
(
internalServerNumber
:
number
,
filename
:
string
)
{
return
selectQuery
(
internalServerNumber
,
`SELECT * FROM "actorImage" WHERE filename = '
${
filename
}
'`
)
.
then
(
rows
=>
rows
[
0
])
}
function
selectQuery
(
internalServerNumber
:
number
,
query
:
string
)
{
const
seq
=
getSequelize
(
internalServerNumber
)
const
options
=
{
type
:
QueryTypes
.
SELECT
as
QueryTypes
.
SELECT
}
...
...
@@ -146,6 +151,7 @@ export {
setPluginVersion
,
setPluginLatestVersion
,
selectQuery
,
getActorImage
,
deleteAll
,
setTokenField
,
updateQuery
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment