Skip to content

Custom thumbs#1731

Open
alexanderstephan wants to merge 21 commits intodevfrom
custom-thumbs
Open

Custom thumbs#1731
alexanderstephan wants to merge 21 commits intodevfrom
custom-thumbs

Conversation

@alexanderstephan
Copy link
Contributor

Motivation and Context

Continuing

Description

Steps for Testing

Prerequisites:

  • 1 Lecturer
  • 2 Students
  • 1 Livestream
  1. Log in
  2. Navigate to a Livestream
  3. ...

Screenshots

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements functionality for uploading custom thumbnails for lectures. It adds a new field isCustomThumbnailEnabled to control whether custom thumbnails can be uploaded, along with UI controls for drag-and-drop thumbnail uploads and backend endpoints to handle the file uploads.

Changes:

  • Added isCustomThumbnailEnabled boolean field to lecture data model and API
  • Implemented drag-and-drop thumbnail upload UI with preview functionality
  • Created backend endpoint and data access method for storing custom thumbnails

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
web/ts/edit-course.ts Added thumbnail upload handlers and preview functionality
web/ts/data-store/admin-lecture-list.ts Added method to upload thumbnail files and update lecture state
web/ts/api/admin-lecture-list.ts Added API interface for custom thumbnail field and upload endpoint
web/template/partial/course/manage/lecture-management-card.gohtml Added UI for custom thumbnail toggle and drag-and-drop upload area
model/stream.go Added CustomThumbnailEnabled field to Stream model
model/file.go Added FILETYPE_THUMB_CUSTOM constant and CourseName field to File model
dao/file.go Added GetThumbnail method to retrieve thumbnails by type
api/stream.go Implemented putCustomLiveThumbnail endpoint and updated getLiveThumbs to use custom thumbnails

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

this.changeSet.commit({ discardKeys: this.videoFiles.map((v) => v.info.key) });
this.uiEditMode = UIEditMode.none;
},
previewThumbnail(e){
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parameter 'e' is ambiguous. Consider renaming it to 'event' or 'dropEvent' to clearly indicate it's a drop event.

Copilot uses AI. Check for mistakes.
Comment on lines +398 to +412
const item = e.dataTransfer.items[0];
const { kind } = item;
switch (kind) {
case "file": {
DataStore.adminLectureList.uploadThumbnail(
this.lectureData.courseId,
this.lectureData.lectureId,
item.getAsFile(),
);
break;
}

}
this.previewThumbnail(e);
}},
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing indentation on line 398. The 'const item' declaration should be indented consistently with the if statement block.

Suggested change
const item = e.dataTransfer.items[0];
const { kind } = item;
switch (kind) {
case "file": {
DataStore.adminLectureList.uploadThumbnail(
this.lectureData.courseId,
this.lectureData.lectureId,
item.getAsFile(),
);
break;
}
}
this.previewThumbnail(e);
}},
const item = e.dataTransfer.items[0];
const { kind } = item;
switch (kind) {
case "file": {
DataStore.adminLectureList.uploadThumbnail(
this.lectureData.courseId,
this.lectureData.lectureId,
item.getAsFile(),
);
break;
}
}
this.previewThumbnail(e);
}},

Copilot uses AI. Check for mistakes.
Comment on lines +237 to +255

const res = await AdminLectureList.uploadThumbnailFile(courseId, lectureId, file);
const newFile = new LectureFile({
id: JSON.parse(res.responseText),
fileType: 2,
friendlyName: file.name,
});

this.data[courseId] = (await this.getData(courseId)).map((s) => {
if (s.lectureId === lectureId) {
return {
...s,
files: [...s.files, newFile],
};
}
return s;
});
await this.triggerUpdate(courseId);

Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent indentation. The function body should start at the standard indentation level without the extra leading spaces.

Suggested change
const res = await AdminLectureList.uploadThumbnailFile(courseId, lectureId, file);
const newFile = new LectureFile({
id: JSON.parse(res.responseText),
fileType: 2,
friendlyName: file.name,
});
this.data[courseId] = (await this.getData(courseId)).map((s) => {
if (s.lectureId === lectureId) {
return {
...s,
files: [...s.files, newFile],
};
}
return s;
});
await this.triggerUpdate(courseId);
const res = await AdminLectureList.uploadThumbnailFile(courseId, lectureId, file);
const newFile = new LectureFile({
id: JSON.parse(res.responseText),
fileType: 2,
friendlyName: file.name,
});
this.data[courseId] = (await this.getData(courseId)).map((s) => {
if (s.lectureId === lectureId) {
return {
...s,
files: [...s.files, newFile],
};
}
return s;
});
await this.triggerUpdate(courseId);

Copilot uses AI. Check for mistakes.
Comment on lines +385 to +393
uploadThumbnailFile: async (
courseId: number,
lectureId: number,
file: File,
listener: PostFormDataListener = {},
) => {
return await uploadFile(`/api/stream/${lectureId}/thumbs/`, file, listener);

},
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The courseId parameter is unused in this function. Either remove it from the parameter list or use it in the API endpoint URL if it's required for the backend route.

Copilot uses AI. Check for mistakes.
if err != nil {

path := pathprovider.LiveThumbnail(streamId)
c.File(path)
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Control flow issue: when err is not nil, the function serves the default thumbnail but then continues to line 191 and attempts to serve file.Path, which may be invalid. Add a return statement after c.File(path) on line 189.

Suggested change
c.File(path)
c.File(path)
return

Copilot uses AI. Check for mistakes.
StreamID: streamID,
Path: path,
Filename: file.Filename,
Type: model.FILETYPE_THUMB_LG_CAM_PRES,
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorrect file type used for custom thumbnail. This should be model.FILETYPE_THUMB_CUSTOM instead of model.FILETYPE_THUMB_LG_CAM_PRES to properly identify custom uploaded thumbnails.

Suggested change
Type: model.FILETYPE_THUMB_LG_CAM_PRES,
Type: model.FILETYPE_THUMB_CUSTOM,

Copilot uses AI. Check for mistakes.
Comment on lines +407 to +417
{{/* </label>*/}}
</section>
{{/* <article x-data="{ id: $id('text-input') }"*/}}
{{/* class="w-full" >*/}}

{{/* </article>*/}}

<!--input type="file" id="thumbnailUpload" class="hidden" accept="image/*" @change="onAttachmentFileDrop"-->



Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove commented-out code. Lines 407, 409-412, and 414 contain unused commented code that should be deleted to improve code clarity.

Suggested change
{{/* </label>*/}}
</section>
{{/* <article x-data="{ id: $id('text-input') }"*/}}
{{/* class="w-full" >*/}}
{{/* </article>*/}}
<!--input type="file" id="thumbnailUpload" class="hidden" accept="image/*" @change="onAttachmentFileDrop"-->
</section>

Copilot uses AI. Check for mistakes.
@joschahenningsen
Copy link
Member

Supersedes #1479

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants