Introducing new table medium, ref #699
This commit is contained in:
@@ -34,7 +34,7 @@ namespace lms::db
|
||||
{
|
||||
namespace
|
||||
{
|
||||
static constexpr Version LMS_DATABASE_VERSION{ 98 };
|
||||
static constexpr Version LMS_DATABASE_VERSION{ 99 };
|
||||
}
|
||||
|
||||
VersionInfo::VersionInfo()
|
||||
@@ -1423,6 +1423,111 @@ WHERE art.image_id IS NULL)");
|
||||
dropIndexes(session);
|
||||
}
|
||||
|
||||
void migrateFromV98(Session& session)
|
||||
{
|
||||
// Medium support
|
||||
dropIndexes(session);
|
||||
|
||||
// New table for mediums
|
||||
utils::executeCommand(*session.getDboSession(), R"(CREATE TABLE IF NOT EXISTS "medium" (
|
||||
"id" integer primary key autoincrement,
|
||||
"version" integer not null,
|
||||
"name" text not null,
|
||||
"position" integer,
|
||||
"track_count" integer,
|
||||
"media" text not null,
|
||||
"replay_gain" real,
|
||||
"release_id" bigint,
|
||||
"preferred_artwork_id" bigint,
|
||||
constraint "fk_medium_release" foreign key ("release_id") references "release" ("id") on delete cascade deferrable initially deferred,
|
||||
constraint "fk_medium_preferred_artwork" foreign key ("preferred_artwork_id") references "artwork" ("id") on delete set null deferrable initially deferred
|
||||
))");
|
||||
|
||||
// New primary key in track -> need to recreate the table
|
||||
utils::executeCommand(*session.getDboSession(), R"(CREATE TABLE IF NOT EXISTS "track_backup" (
|
||||
"id" integer primary key autoincrement,
|
||||
"version" integer not null,
|
||||
"scan_version" integer not null,
|
||||
"track_number" integer,
|
||||
"name" text not null,
|
||||
"duration" integer,
|
||||
"bitrate" integer not null,
|
||||
"bits_per_sample" integer not null,
|
||||
"channel_count" integer not null,
|
||||
"sample_rate" integer not null,
|
||||
"date" text,
|
||||
"original_date" text,
|
||||
"absolute_file_path" text not null,
|
||||
"file_size" bigint not null,
|
||||
"file_last_write" text,
|
||||
"file_added" text,
|
||||
"mbid" text not null,
|
||||
"recording_mbid" text not null,
|
||||
"copyright" text not null,
|
||||
"copyright_url" text not null,
|
||||
"advisory" integer not null,
|
||||
"replay_gain" real,
|
||||
"artist_display_name" text not null,
|
||||
"comment" text not null,
|
||||
"medium_id" bigint,
|
||||
"release_id" bigint,
|
||||
"media_library_id" bigint,
|
||||
"directory_id" bigint,
|
||||
"preferred_artwork_id" bigint,
|
||||
"preferred_media_artwork_id" bigint,
|
||||
constraint "fk_track_medium" foreign key ("medium_id") references "medium" ("id") on delete cascade deferrable initially deferred,
|
||||
constraint "fk_track_release" foreign key ("release_id") references "release" ("id") on delete cascade deferrable initially deferred,
|
||||
constraint "fk_track_media_library" foreign key ("media_library_id") references "media_library" ("id") on delete set null deferrable initially deferred,
|
||||
constraint "fk_track_directory" foreign key ("directory_id") references "directory" ("id") on delete cascade deferrable initially deferred,
|
||||
constraint "fk_track_preferred_artwork" foreign key ("preferred_artwork_id") references "artwork" ("id") on delete set null deferrable initially deferred,
|
||||
constraint "fk_track_preferred_media_artwork" foreign key ("preferred_media_artwork_id") references "artwork" ("id") on delete set null deferrable initially deferred
|
||||
))");
|
||||
|
||||
// Migrate data:
|
||||
// - removed disc_number, total_track, disc_subtitle, release_replay_gain
|
||||
// - renamed track_replay_gain to replay_gain
|
||||
// - with the new medium_id field set to null
|
||||
utils::executeCommand(*session.getDboSession(), R"(INSERT INTO track_backup
|
||||
SELECT
|
||||
id,
|
||||
version,
|
||||
scan_version,
|
||||
track_number,
|
||||
name,
|
||||
duration,
|
||||
bitrate,
|
||||
bits_per_sample,
|
||||
channel_count,
|
||||
sample_rate,
|
||||
date,
|
||||
original_date,
|
||||
absolute_file_path,
|
||||
file_size,
|
||||
file_last_write,
|
||||
file_added,
|
||||
mbid,
|
||||
recording_mbid,
|
||||
copyright,
|
||||
copyright_url,
|
||||
advisory,
|
||||
track_replay_gain AS replay_gain,
|
||||
artist_display_name,
|
||||
comment,
|
||||
NULL as medium_id,
|
||||
release_id,
|
||||
media_library_id,
|
||||
directory_id,
|
||||
preferred_artwork_id,
|
||||
preferred_media_artwork_id
|
||||
FROM track)");
|
||||
|
||||
utils::executeCommand(*session.getDboSession(), "DROP TABLE track");
|
||||
utils::executeCommand(*session.getDboSession(), "ALTER TABLE track_backup RENAME TO track");
|
||||
|
||||
// Just increment the scan version of the settings to make the next scan rescan all audio files
|
||||
utils::executeCommand(*session.getDboSession(), "UPDATE scan_settings SET artist_info_scan_version = artist_info_scan_version + 1");
|
||||
}
|
||||
|
||||
bool doDbMigration(Session& session)
|
||||
{
|
||||
constexpr std::string_view outdatedMsg{ "Outdated database, please rebuild it (delete the .db file and restart)" };
|
||||
@@ -1497,6 +1602,7 @@ WHERE art.image_id IS NULL)");
|
||||
{ 95, migrateFromV95 },
|
||||
{ 96, migrateFromV96 },
|
||||
{ 97, migrateFromV97 },
|
||||
{ 98, migrateFromV98 },
|
||||
};
|
||||
|
||||
bool migrationPerformed{};
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "database/objects/Image.hpp"
|
||||
#include "database/objects/Listen.hpp"
|
||||
#include "database/objects/MediaLibrary.hpp"
|
||||
#include "database/objects/Medium.hpp"
|
||||
#include "database/objects/PlayListFile.hpp"
|
||||
#include "database/objects/PlayQueue.hpp"
|
||||
#include "database/objects/RatedArtist.hpp"
|
||||
@@ -82,6 +83,7 @@ namespace lms::db
|
||||
_session.mapClass<Label>("label");
|
||||
_session.mapClass<Listen>("listen");
|
||||
_session.mapClass<MediaLibrary>("media_library");
|
||||
_session.mapClass<Medium>("medium");
|
||||
_session.mapClass<PlayListFile>("playlist_file");
|
||||
_session.mapClass<PlayQueue>("playqueue");
|
||||
_session.mapClass<RatedArtist>("rated_artist");
|
||||
@@ -235,6 +237,8 @@ namespace lms::db
|
||||
|
||||
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS media_library_id_idx ON media_library(id)");
|
||||
|
||||
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS medium_release_position_idx ON medium(release_id, position)");
|
||||
|
||||
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS playlist_file_id_idx ON playlist_file(id)");
|
||||
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS playlist_file_directory_idx ON playlist_file(directory_id);");
|
||||
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS playlist_file_absolute_file_path_idx ON playlist_file(absolute_file_path)");
|
||||
@@ -262,12 +266,12 @@ namespace lms::db
|
||||
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_file_last_write_idx ON track(file_last_write)");
|
||||
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_media_library_idx ON track(media_library_id)");
|
||||
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_media_library_release_idx ON track(media_library_id, release_id)");
|
||||
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_medium_idx ON track(medium_id)");
|
||||
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_mbid_idx ON track(mbid)");
|
||||
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_name_file_size_idx ON track(name, file_size)");
|
||||
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_name_nocase_idx ON track(name COLLATE NOCASE)");
|
||||
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_original_date_idx ON track(original_date)");
|
||||
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_recording_mbid_idx ON track(recording_mbid)");
|
||||
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_release_disc_idx ON track(release_id, disc_number)");
|
||||
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_release_date_idx ON track(release_id, date)");
|
||||
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_release_file_last_write_idx ON track(release_id, file_last_write)");
|
||||
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_release_file_added_idx ON track(release_id, file_added)");
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "database/objects/Artwork.hpp"
|
||||
#include "database/objects/Directory.hpp"
|
||||
#include "database/objects/MediaLibrary.hpp"
|
||||
#include "database/objects/Medium.hpp"
|
||||
#include "database/objects/Release.hpp"
|
||||
#include "database/objects/Track.hpp"
|
||||
#include "database/objects/TrackArtistLink.hpp"
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2025 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "database/objects/Medium.hpp"
|
||||
|
||||
#include <Wt/Dbo/Impl.h>
|
||||
|
||||
#include "database/Session.hpp"
|
||||
#include "database/objects/Artist.hpp"
|
||||
#include "database/objects/Artwork.hpp"
|
||||
#include "database/objects/Cluster.hpp"
|
||||
#include "database/objects/Directory.hpp"
|
||||
#include "database/objects/MediaLibrary.hpp"
|
||||
#include "database/objects/Release.hpp"
|
||||
#include "database/objects/Track.hpp"
|
||||
#include "database/objects/TrackArtistLink.hpp"
|
||||
#include "database/objects/TrackEmbeddedImage.hpp"
|
||||
#include "database/objects/TrackEmbeddedImageLink.hpp"
|
||||
#include "database/objects/TrackLyrics.hpp"
|
||||
|
||||
#include "Utils.hpp"
|
||||
#include "traits/IdTypeTraits.hpp"
|
||||
|
||||
DBO_INSTANTIATE_TEMPLATES(lms::db::Medium);
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
Medium::Medium(ObjectPtr<Release> release)
|
||||
: _release(getDboPtr(release))
|
||||
{
|
||||
}
|
||||
|
||||
Medium::pointer Medium::create(Session& session, ObjectPtr<Release> release)
|
||||
{
|
||||
return session.getDboSession()->add(std::unique_ptr<Medium>{ new Medium{ release } });
|
||||
}
|
||||
|
||||
std::size_t Medium::getCount(Session& session)
|
||||
{
|
||||
session.checkReadTransaction();
|
||||
|
||||
return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT COUNT(*) FROM medium"));
|
||||
}
|
||||
|
||||
Medium::pointer Medium::find(Session& session, MediumId id)
|
||||
{
|
||||
session.checkReadTransaction();
|
||||
|
||||
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<Medium>>("SELECT m from medium m").where("m.id = ?").bind(id));
|
||||
}
|
||||
|
||||
Medium::pointer Medium::find(Session& session, ReleaseId releaseId, std::optional<std::size_t> position)
|
||||
{
|
||||
session.checkReadTransaction();
|
||||
|
||||
std::optional<int> dbPosition;
|
||||
if (position)
|
||||
dbPosition = static_cast<int>(*position);
|
||||
|
||||
auto query{ session.getDboSession()->query<Wt::Dbo::ptr<Medium>>("SELECT m from medium m") };
|
||||
query.where("m.release_id = ?").bind(releaseId);
|
||||
if (position)
|
||||
query.where("m.position = ?").bind(*dbPosition);
|
||||
else
|
||||
query.where("m.position IS NULL");
|
||||
|
||||
return utils::fetchQuerySingleResult(query);
|
||||
}
|
||||
|
||||
} // namespace lms::db
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "database/objects/Cluster.hpp"
|
||||
#include "database/objects/Directory.hpp"
|
||||
#include "database/objects/MediaLibrary.hpp"
|
||||
#include "database/objects/Medium.hpp"
|
||||
#include "database/objects/Release.hpp"
|
||||
#include "database/objects/Track.hpp"
|
||||
#include "database/objects/TrackArtistLink.hpp"
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "database/objects/Cluster.hpp"
|
||||
#include "database/objects/Directory.hpp"
|
||||
#include "database/objects/MediaLibrary.hpp"
|
||||
#include "database/objects/Medium.hpp"
|
||||
#include "database/objects/Track.hpp"
|
||||
#include "database/objects/TrackArtistLink.hpp"
|
||||
#include "database/objects/TrackEmbeddedImage.hpp"
|
||||
@@ -577,28 +578,6 @@ namespace lms::db
|
||||
return utils::fetchQuerySingleResult(createQuery<int>(session, "COUNT(DISTINCT r.id)", params));
|
||||
}
|
||||
|
||||
std::size_t Release::getDiscCount() const
|
||||
{
|
||||
assert(session());
|
||||
int res{ utils::fetchQuerySingleResult(session()->query<int>("SELECT COUNT(DISTINCT disc_number) FROM track t").where("t.release_id = ?").bind(getId())) };
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<DiscInfo> Release::getDiscs() const
|
||||
{
|
||||
assert(session());
|
||||
|
||||
using ResultType = std::tuple<int, std::string>;
|
||||
const auto query{ session()->query<ResultType>("SELECT DISTINCT disc_number, disc_subtitle FROM track t").where("t.release_id = ?").bind(getId()).orderBy("disc_number") };
|
||||
|
||||
std::vector<DiscInfo> discs;
|
||||
utils::forEachQueryResult(query, [&](ResultType&& res) {
|
||||
discs.emplace_back(DiscInfo{ static_cast<std::size_t>(std::get<int>(res)), std::move(std::get<std::string>(res)) });
|
||||
});
|
||||
|
||||
return discs;
|
||||
}
|
||||
|
||||
core::PartialDateTime Release::getDate() const
|
||||
{
|
||||
return getDate(false);
|
||||
@@ -753,6 +732,18 @@ namespace lms::db
|
||||
return _preferredArtwork.id();
|
||||
}
|
||||
|
||||
std::vector<ObjectPtr<Medium>> Release::getMediums() const
|
||||
{
|
||||
assert(session());
|
||||
|
||||
// Select the similar releases using the 5 most used clusters of the release
|
||||
auto query{ session()->query<Wt::Dbo::ptr<Medium>>("SELECT m from medium m") };
|
||||
query.where("m.release_id = ?").bind(getId());
|
||||
query.orderBy("m.position");
|
||||
|
||||
return utils::fetchQueryResults<Medium::pointer>(query);
|
||||
}
|
||||
|
||||
void Release::clearLabels()
|
||||
{
|
||||
_labels.clear();
|
||||
@@ -794,11 +785,6 @@ namespace lms::db
|
||||
return getArtists().size() > 1;
|
||||
}
|
||||
|
||||
bool Release::hasDiscSubtitle() const
|
||||
{
|
||||
return utils::fetchQuerySingleResult(session()->query<int>("SELECT EXISTS (SELECT 1 FROM track WHERE disc_subtitle IS NOT NULL AND disc_subtitle <> '' AND release_id = ?)").bind(getId()));
|
||||
}
|
||||
|
||||
std::size_t Release::getTrackCount() const
|
||||
{
|
||||
assert(session());
|
||||
|
||||
@@ -24,11 +24,13 @@
|
||||
|
||||
#include "core/ILogger.hpp"
|
||||
#include "database/Session.hpp"
|
||||
#include "database/Types.hpp"
|
||||
#include "database/objects/Artist.hpp"
|
||||
#include "database/objects/Artwork.hpp"
|
||||
#include "database/objects/Cluster.hpp"
|
||||
#include "database/objects/Directory.hpp"
|
||||
#include "database/objects/MediaLibrary.hpp"
|
||||
#include "database/objects/Medium.hpp"
|
||||
#include "database/objects/Release.hpp"
|
||||
#include "database/objects/TrackArtistLink.hpp"
|
||||
#include "database/objects/TrackEmbeddedImage.hpp"
|
||||
@@ -146,6 +148,9 @@ namespace lms::db
|
||||
query.where("r.name = ?").bind(params.releaseName);
|
||||
}
|
||||
|
||||
if (params.medium.isValid())
|
||||
query.where("t.medium_id = ?").bind(params.medium);
|
||||
|
||||
if (params.trackList.isValid() || params.sortMethod == TrackSortMethod::TrackList)
|
||||
{
|
||||
query.join("tracklist t_l ON t_l_e.tracklist_id = t_l.id");
|
||||
@@ -156,8 +161,11 @@ namespace lms::db
|
||||
if (params.trackNumber)
|
||||
query.where("t.track_number = ?").bind(*params.trackNumber);
|
||||
|
||||
if (params.discNumber)
|
||||
query.where("t.disc_number = ?").bind(*params.discNumber);
|
||||
if (params.sortMethod == TrackSortMethod::DateDescAndRelease
|
||||
|| params.sortMethod == TrackSortMethod::Release)
|
||||
{
|
||||
query.join("medium m ON t.medium_id = m.id");
|
||||
}
|
||||
|
||||
if (params.filters.mediaLibrary.isValid())
|
||||
query.where("t.media_library_id = ?").bind(params.filters.mediaLibrary);
|
||||
@@ -213,16 +221,19 @@ namespace lms::db
|
||||
query.orderBy("t.absolute_file_path COLLATE NOCASE");
|
||||
break;
|
||||
case TrackSortMethod::DateDescAndRelease:
|
||||
query.orderBy("t.date DESC,t.release_id,t.disc_number,t.track_number");
|
||||
query.orderBy("t.date DESC,t.release_id,m.position,t.track_number");
|
||||
break;
|
||||
case TrackSortMethod::Release:
|
||||
query.orderBy("t.disc_number,t.track_number");
|
||||
query.orderBy("m.position,t.track_number");
|
||||
break;
|
||||
case TrackSortMethod::TrackList:
|
||||
assert(params.trackList.isValid());
|
||||
query.orderBy("t_l_e.id");
|
||||
break;
|
||||
case TrackSortMethod::TrackNumber:
|
||||
query.orderBy("t.track_number");
|
||||
break;
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
@@ -360,7 +371,7 @@ namespace lms::db
|
||||
{
|
||||
session.checkReadTransaction();
|
||||
|
||||
auto query{ session.getDboSession()->query<TrackId>("SELECT track.id FROM track WHERE mbid in (SELECT mbid FROM track WHERE mbid <> '' GROUP BY mbid HAVING COUNT (*) > 1)").orderBy("track.release_id,track.disc_number,track.track_number,track.mbid") };
|
||||
auto query{ session.getDboSession()->query<TrackId>("SELECT track.id FROM track WHERE mbid in (SELECT mbid FROM track WHERE mbid <> '' GROUP BY mbid HAVING COUNT (*) > 1)").orderBy("track.release_id,track.mbid") };
|
||||
|
||||
return utils::execRangeQuery<TrackId>(query, range);
|
||||
}
|
||||
|
||||
@@ -43,8 +43,7 @@ namespace lms::db
|
||||
|
||||
auto query{ session.getDboSession()->query<Wt::Dbo::ptr<TrackEmbeddedImage>>("SELECT t_e_i FROM track_embedded_image t_e_i") };
|
||||
|
||||
if (params.artist.isValid()
|
||||
|| params.discNumber.has_value()
|
||||
if (params.medium.isValid()
|
||||
|| params.track.isValid()
|
||||
|| params.release.isValid()
|
||||
|| params.trackList.isValid()
|
||||
@@ -54,39 +53,27 @@ namespace lms::db
|
||||
{
|
||||
query.join("track_embedded_image_link t_e_i_l ON t_e_i_l.track_embedded_image_id = t_e_i.id");
|
||||
|
||||
if (params.artist.isValid())
|
||||
{
|
||||
query.join("track_artist_link t_a_l ON t_a_l.track_id = t_e_i_l.track_id");
|
||||
query.where("t_a_l.artist_id = ?").bind(params.artist);
|
||||
|
||||
if (!params.trackArtistLinkTypes.empty())
|
||||
{
|
||||
std::string clause{ "t_a_l.type IN (" };
|
||||
for (const auto& type : params.trackArtistLinkTypes)
|
||||
{
|
||||
if (clause.back() != '(')
|
||||
clause += ",";
|
||||
clause += "?";
|
||||
query.bind(type);
|
||||
}
|
||||
clause += ")";
|
||||
query.where(clause);
|
||||
}
|
||||
}
|
||||
|
||||
if (params.track.isValid())
|
||||
query.where("t_e_i_l.track_id = ?").bind(params.track);
|
||||
|
||||
if (params.release.isValid()
|
||||
|| params.discNumber.has_value()
|
||||
|| params.medium.isValid()
|
||||
|| params.sortMethod == TrackEmbeddedImageSortMethod::DiscNumberThenTrackNumberThenSizeDesc
|
||||
|| params.sortMethod == TrackEmbeddedImageSortMethod::TrackNumberThenSizeDesc)
|
||||
{
|
||||
assert(!(params.release.isValid() && params.medium.isValid()));
|
||||
|
||||
assert((params.sortMethod != TrackEmbeddedImageSortMethod::DiscNumberThenTrackNumberThenSizeDesc || params.release.isValid()));
|
||||
assert((params.sortMethod != TrackEmbeddedImageSortMethod::TrackNumberThenSizeDesc || params.medium.isValid()));
|
||||
|
||||
query.join("track t ON t_e_i_l.track_id = t.id");
|
||||
if (params.release.isValid())
|
||||
query.where("t.release_id = ?").bind(params.release);
|
||||
if (params.discNumber.has_value())
|
||||
query.where("t.disc_number = ?").bind(params.discNumber.value());
|
||||
if (params.medium.isValid())
|
||||
query.where("t.medium_id = ?").bind(params.medium);
|
||||
|
||||
if (params.sortMethod == TrackEmbeddedImageSortMethod::DiscNumberThenTrackNumberThenSizeDesc)
|
||||
query.join("medium m ON m.id = t.medium_id");
|
||||
}
|
||||
|
||||
if (params.trackList.isValid())
|
||||
@@ -107,7 +94,7 @@ namespace lms::db
|
||||
query.orderBy("t_e_i.size DESC");
|
||||
break;
|
||||
case TrackEmbeddedImageSortMethod::DiscNumberThenTrackNumberThenSizeDesc:
|
||||
query.orderBy("t.disc_number, t.track_number, t_e_i.size DESC");
|
||||
query.orderBy("m.position, t.track_number, t_e_i.size DESC");
|
||||
break;
|
||||
case TrackEmbeddedImageSortMethod::TrackNumberThenSizeDesc:
|
||||
query.orderBy("t.track_number, t_e_i.size DESC");
|
||||
|
||||
Reference in New Issue
Block a user