Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/movie support #8

Merged
merged 10 commits into from
Feb 19, 2023
Merged
4 changes: 2 additions & 2 deletions Client/Script/BulkActionCommon.js
Original file line number Diff line number Diff line change
Expand Up @@ -386,9 +386,9 @@ class BulkActionCommon {
static sortMarkerList(markers, episodeData) {
return markers.sort((a, b) => {
/** @type {SerializedEpisodeData} */
const aEd = episodeData[a.episodeId];
const aEd = episodeData[a.parentId];
/** @type {SerializedEpisodeData} */
const bEd = episodeData[b.episodeId];
const bEd = episodeData[b.parentId];
if (aEd.seasonIndex != bEd.seasonIndex) { return aEd.seasonIndex - bEd.seasonIndex; }
if (aEd.index != bEd.index) { return aEd.index - bEd.index; }
return a.start - b.start;
Expand Down
4 changes: 2 additions & 2 deletions Client/Script/BulkDeleteOverlay.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class BulkDeleteOverlay {
);

for (const marker of sortedMarkers) {
this.#table.addRow(new BulkDeleteRow(this.#table, marker, data.episodeData[marker.episodeId]));
this.#table.addRow(new BulkDeleteRow(this.#table, marker, data.episodeData[marker.parentId]));
}

$('#bulkActionContainer').appendChild(this.#table.html());
Expand Down Expand Up @@ -113,7 +113,7 @@ class BulkDeleteRow extends BulkActionRow {
/** Construct the table row. */
build() {
const row = this.buildRow(
this.createCheckbox(true /*checked*/, this.#marker.id, this.#marker.episodeId),
this.createCheckbox(true /*checked*/, this.#marker.id, this.#marker.parentId),
`S${pad0(this.#episode.seasonIndex, 2)}E${pad0(this.#episode.index, 2)}`,
TableElements.customClassColumn(this.#episode.title, 'bulkActionEpisodeColumn'),
TableElements.timeData(this.#marker.start),
Expand Down
8 changes: 4 additions & 4 deletions Client/Script/BulkShiftOverlay.js
Original file line number Diff line number Diff line change
Expand Up @@ -367,9 +367,9 @@ class BulkShiftOverlay {
const sortedMarkers = BulkActionCommon.sortMarkerList(shiftResult.allMarkers, shiftResult.episodeData);
for (let i = 0; i < sortedMarkers.length; ++i) {
let checkGroup = [];
const eInfo = shiftResult.episodeData[sortedMarkers[i].episodeId];
const eInfo = shiftResult.episodeData[sortedMarkers[i].parentId];
checkGroup.push(sortedMarkers[i]);
while (i < sortedMarkers.length - 1 && sortedMarkers[i+1].episodeId == eInfo.metadataId) {
while (i < sortedMarkers.length - 1 && sortedMarkers[i+1].parentId == eInfo.metadataId) {
checkGroup.push(sortedMarkers[++i]);
}

Expand Down Expand Up @@ -463,7 +463,7 @@ class BulkShiftRow extends BulkActionRow {
this.#linked = linked;
}

episodeId() { return this.#marker.episodeId; }
episodeId() { return this.#marker.parentId; }
markerId() { return this.#marker.id; }
/** Returns whether this row is linked to other rows that share the same episode id. */
linked() { return this.#linked; }
Expand All @@ -477,7 +477,7 @@ class BulkShiftRow extends BulkActionRow {
/** Build and return the marker row. */
build() {
const row = this.buildRow(
this.createCheckbox(!this.#linked, this.#marker.id, this.#marker.episodeId, { linked : this.#linked ? 1 : 0 }),
this.createCheckbox(!this.#linked, this.#marker.id, this.#marker.parentId, { linked : this.#linked ? 1 : 0 }),
`S${pad0(this.#episode.seasonIndex, 2)}E${pad0(this.#episode.index, 2)}`,
TableElements.timeData(this.#marker.start),
TableElements.timeData(this.#marker.end),
Expand Down
119 changes: 119 additions & 0 deletions Client/Script/ClientDataExtensions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { Log } from "../../Shared/ConsoleLog.js";
import { EpisodeData, MarkerData, MovieData, PlexData } from "../../Shared/PlexTypes.js";
import MarkerTable from "./MarkerTable.js";
import { EpisodeResultRow, MovieResultRow } from "./ResultRow.js";

/**
* Note: This class is never actually instantiated. It's only used for
* intellisense to get around issues arising from JS's inability to support multiple inheritance. */
class MediaItemWithMarkerTable extends PlexData {
/**
* The duration of this media item, in milliseconds.
* @type {number} */
duration;
constructor() { super(); throw new Error(`We shouldn't ever actually create a MediaItemWithMarkerTable`); }
/** @returns {MarkerTable} */
markerTable() { return null; }
}

/**
* An extension of the client/server-agnostic MovieData to include client-specific functionality (connecting with the marker table)
*
* NOTE: This should really be shared with ClientEpisodeData, but to do that correctly, we need multiple inheritance, which isn't
* possible in JS. We want MovieData's base fields, and ClientEpisodeData wants EpisodeData's base fields, but both client
* classes want client-specific methods that can't be added to the distinct base types. There are some hacks that could be
* used, but I've opted to duplicate the code for now.
*/
class ClientMovieData extends MovieData {

/**
* The UI representation of the markers
* @type {MarkerTable} */
#markerTable = null;

/** @param {Object<string, any>} [movie] */
constructor(movie) {
super(movie);
}

/**
* Creates the marker table for this episode.
* @param {MovieResultRow} parentRow The UI associated with this episode.
* @param {{[metadataId: number]: Object[]}} serializedMarkers Map of episode ids to an array of
* serialized {@linkcode MarkerData} for the episode. */
createMarkerTable(parentRow, serializedMarkers) {
if (this.#markerTable != null) {
Log.warn('The marker table already exists, we shouldn\'t be creating a new one!');
}

const markers = [];
for (const marker of serializedMarkers) {
markers.push(new MarkerData().setFromJson(marker));
}

const mov = parentRow.movie();

// Marker breakdown is currently overkill for movies, since it only ever has a single item inside of it.
// If intros/credits are ever separated though, this will do the right thing.
const markerCount = mov?.markerBreakdown ? Object.keys(mov.markerBreakdown).reduce((sum, k) => sum + k * mov.markerBreakdown[k]) : 0;
this.#markerTable = new MarkerTable(markers, parentRow, true /*lazyLoad*/, markerCount);
}

/**
* @param {SerializedMarkerData} serializedMarkers */
initializeMarkerTable(serializedMarkers) {
if (this.#markerTable == null) {
Log.error(`Can't initialize marker table if it hasn't been created yet.`);
return;
}

const markers = [];
for (const marker of serializedMarkers) {
markers.push(new MarkerData().setFromJson(marker));
}

this.#markerTable.lazyInit(markers);
}

/** @returns {MarkerTable} */
markerTable() { return this.#markerTable; }
}

/**
* An extension of the client/server-agnostic EpisodeData to include client-specific functionality
*/
class ClientEpisodeData extends EpisodeData {

/**
* The UI representation of the markers
* @type {MarkerTable} */
#markerTable = null;

/** @param {Object<string, any>} [episode] */
constructor(episode) {
super(episode);
}

/**
* Creates the marker table for this episode.
* @param {EpisodeResultRow} parentRow The UI associated with this episode.
* @param {{[metadataId: number]: Object[]}} serializedMarkers Map of episode ids to an array of
* serialized {@linkcode MarkerData} for the episode. */
createMarkerTable(parentRow, serializedMarkers) {
if (this.#markerTable != null) {
Log.warn('The marker table already exists, we shouldn\'t be creating a new one!');
}

const markers = [];
for (const marker of serializedMarkers) {
markers.push(new MarkerData().setFromJson(marker));
}

this.#markerTable = new MarkerTable(markers, parentRow);
}

/** @returns {MarkerTable} */
markerTable() { return this.#markerTable; }
}

export { MediaItemWithMarkerTable, ClientEpisodeData, ClientMovieData };
88 changes: 0 additions & 88 deletions Client/Script/ClientEpisodeData.js

This file was deleted.

16 changes: 12 additions & 4 deletions Client/Script/Common.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Overlay from './inc/Overlay.js';
import ServerPausedOverlay from './ServerPausedOverlay.js';
/** @typedef {!import('../../Shared/PlexTypes.js').SerializedBulkAddResult} SerializedBulkAddResult */
/** @typedef {!import('../../Shared/PlexTypes.js').SerializedMarkerData} SerializedMarkerData */
/** @typedef {!import('../../Shared/PlexTypes.js').SerializedMovieData} SerializedMovieData */
/** @typedef {!import('../../Shared/PlexTypes.js').SerializedShowData} SerializedShowData */
/** @typedef {!import('../../Shared/PlexTypes.js').SerializedEpisodeData} SerializedEpisodeData */
/** @typedef {!import('../../Shared/PlexTypes.js').SerializedSeasonData} SerializedSeasonData */
Expand Down Expand Up @@ -117,18 +118,18 @@ const ServerCommand = {
/**
* Retrieve markers for all episodes ids in `keys`.
* @param {number[]} keys The list of episode ids to grab the markers of.
* @returns {Promise<SerializedMarkerData[]>} */
* @returns {Promise<{[metadataId: number]: SerializedMarkerData[]}>} */
query : async (keys) => jsonRequest('query', { keys : keys.join(',') }),

/**
* Retrieve all TV library sections in the database.
* @returns {Promise<{id: number, name: string}[]} */
* Retrieve all Movie/TV library sections in the database.
* @returns {Promise<{id: number, type : number, name: string}[]} */
getSections : async () => jsonRequest('get_sections'),

/**
* Retrieve all shows in the given section.
* @param {number} id
* @returns {Promise<SerializedShowData[]>} */
* @returns {Promise<SerializedShowData[]|SerializedMovieData[]>} */
getSection : async (id) => jsonRequest('get_section', { id : id }),

/**
Expand All @@ -143,6 +144,13 @@ const ServerCommand = {
* @returns {Promise<SerializedEpisodeData>} */
getEpisodes : async (id) => jsonRequest('get_episodes', { id : id }),

/**
* Return whether the given metadata item has thumbnails associated with it.
* Only valid for episode/movie metadata ids.
* @param {number} id
* @returns {Promise<{hasThumbnails: boolean}>} */
checkForThumbnails : async (id) => jsonRequest('check_thumbs', { id : id }),

/**
* Retrieve marker breakdown stats for the given section.
* @param {number} id
Expand Down
Loading