Commit d74206b3 authored by Jian Li's avatar Jian Li
Browse files

Media:Filename sorting improvement

parent faa80596
Pipeline #12606 passed with stage
in 30 minutes and 58 seconds
......@@ -882,7 +882,16 @@ std::string Media::sortRequest( const QueryParameters* params )
desc = !desc; // Make decreasing order default for play count sorting
break;
case SortingCriteria::Filename:
req += "m.filename";
if(desc == true)
{
req += "trim(remove_ext(m.filename),'0123456789') collate NOCASE DESC,";
req += "cast(m.filename as INTEGER) DESC,";
req += "suffix_number(m.filename) DESC";
}else{
req += "trim(remove_ext(m.filename),'0123456789') collate NOCASE ASC,";
req += "cast(m.filename as INTEGER) ASC, suffix_number(m.filename) ASC";
}
descAdded = true;
break;
case SortingCriteria::LastModificationDate:
req += "f.last_modification_date";
......@@ -898,7 +907,15 @@ std::string Media::sortRequest( const QueryParameters* params )
descAdded = true;
break;
case SortingCriteria::Artist:
req += "art.name";
if ( desc == true ){
req += "trim(art.name,'0123456789') collate NOCASE DESC,cast(art.name as INTEGER) DESC,";
req += "art.name collate SUFFIXNUMBER DESC";
}
else{
req += "trim(art.name,'0123456789') collate NOCASE , cast(art.name as INTEGER),";
req += "art.name collate SUFFIXNUMBER ";
}
descAdded = true;
break;
case SortingCriteria::TrackId:
if ( desc == true )
......@@ -912,7 +929,15 @@ std::string Media::sortRequest( const QueryParameters* params )
/* fall-through */
case SortingCriteria::Default:
case SortingCriteria::Alpha:
req += "m.title";
if( desc == true ){
req += "trim(m.title,'0123456789') collate NOCASE DESC, cast(m.title as INTEGER),";
req += "m.title collate SUFFIXNUMBER DESC";
}
else{
req += "trim(m.title,'0123456789') collate NOCASE, cast(m.title as INTEGER),";
req += "m.title collate SUFFIXNUMBER";
}
descAdded = true;
break;
}
if ( desc == true && !descAdded )
......
......@@ -28,13 +28,14 @@
#include "database/SqliteTools.h"
#include "utils/Filename.h"
#include <cstring>
namespace medialibrary
{
namespace sqlite
{
const int SMARTNUMBER_LEN = 20;
Connection::Connection( const std::string& dbPath )
: m_dbPath( dbPath )
, m_readLock( m_contextLock )
......@@ -98,6 +99,9 @@ Connection::Handle Connection::handle()
m_conns.emplace( compat::this_thread::get_id(), std::move( dbConn ) );
sqlite3_update_hook( dbConnection, &updateHook, this );
static thread_local ThreadSpecificConnection tsc( shared_from_this() );
sqlite3_create_collation(dbConnection, "SUFFIXNUMBER", SQLITE_UTF8, dbConnection, &suffixNumberCollation);
sqlite3_create_function(dbConnection, "remove_ext", 1, SQLITE_UTF8, dbConnection, &removeExt, NULL,NULL);
sqlite3_create_function(dbConnection, "suffix_number", 1, SQLITE_UTF8, dbConnection, &suffixNumber, NULL,NULL);
return dbConnection;
}
return it->second.get();
......@@ -244,6 +248,38 @@ void Connection::updateHook( void* data, int reason, const char*,
}
}
void Connection::removeExt(sqlite3_context* ctx, int argc, sqlite3_value** argv){
const char *z2;
int n;
(void)argc;
z2 = (char*)sqlite3_value_text(argv[0]);
n = sqlite3_value_bytes(argv[0]);
const char *ptr = strrchr(z2, '.');
if(ptr)
n = ptr-z2;
sqlite3_result_text64(ctx,z2,n,SQLITE_TRANSIENT,SQLITE_UTF8);
}
void Connection::suffixNumber(sqlite3_context* ctx, int argc, sqlite3_value** argv){
const char *z2;
(void)argc;
z2 = (char*)sqlite3_value_text(argv[0]);
sqlite3_result_int64(ctx,utils::file::suffixNumber(z2));
}
int Connection::suffixNumberCollation(void* data, int len1, const void* s1, int len2, const void* s2)
{
unsigned long long l1;
unsigned long long l2;
l1 = utils::file::suffixNumber((char*)s1);
l2 = utils::file::suffixNumber((char*)s2);
if(l1<l2){
return -1;
}else if(l1>l2){
return 1;
}
return 0;
}
Connection::WeakDbContext::WeakDbContext( Connection* conn )
: m_conn( conn )
{
......
......@@ -108,6 +108,10 @@ private:
const std::string& value );
static void updateHook( void* data, int reason, const char* database,
const char* table, sqlite_int64 rowId );
static int suffixNumberCollation(void* data, int len1, const void* s1, int len2, const void* s2);
static void removeExt(sqlite3_context* ctx, int argc, sqlite3_value** argv);
static void suffixNumber(sqlite3_context* ctx, int argc, sqlite3_value** argv);
private:
struct ThreadSpecificConnection
......
......@@ -46,6 +46,18 @@ namespace utils
namespace file
{
unsigned long long suffixNumber( const std::string& fileName)
{
auto name = stripExtension(fileName);
auto tail = name.back();
if(tail<'0'||tail>'9') return 0;
auto pos = name.find_last_not_of("0123456789");
if(pos==std::string::npos){
return std::stoul(name);
}
return std::stoul(name.substr(pos+1));
}
std::string extension( const std::string& fileName )
{
auto pos = fileName.find_last_of( '.' );
......
......@@ -33,6 +33,11 @@ namespace utils
namespace file
{
/**
* @brief suffixNumber Returns the numeric suffix of the file's name without the extension.
* @param fileName A filename
*/
unsigned long long suffixNumber( const std::string& fileName);
/**
* @brief extension Returns the file's extension, without the leading '.'
* @param fileName A filename
......
......@@ -199,3 +199,12 @@ TEST( FsUtils, stripExtension )
ASSERT_EQ( "dummy", utils::file::stripExtension( "dummy" ) );
ASSERT_EQ( "test.with.dot", utils::file::stripExtension( "test.with.dot.ext" ) );
}
TEST( FsUtils, suffixNumber)
{
ASSERT_EQ( 123ull, utils::file::suffixNumber( "seaOtter123.mkv" ) );
ASSERT_EQ( 123ull, utils::file::suffixNumber( "123.mkv" ) );
ASSERT_EQ( 0ull, utils::file::suffixNumber( "" ) );
ASSERT_EQ( 0ull, utils::file::suffixNumber( "dummy" ) );
ASSERT_EQ( 123ull, utils::file::suffixNumber( "test.with.dot123.ext" ) );
}
......@@ -559,6 +559,59 @@ TEST_F( Medias, SortByFileSize )
ASSERT_EQ( m1->id(), media[0]->id() );
}
TEST_F( Medias, SortByPostNumberFilename2 )
{
auto m1 = std::static_pointer_cast<Media>( ml->addMedia( "zzzzz.mp3", Media::Type::Video ) );
m1->setTitle( "aaaaa", false );
auto m2 = std::static_pointer_cast<Media>( ml->addMedia( "aaaaa.mp3", Media::Type::Video ) );
m2->setTitle( "zzzzz", false );
QueryParameters params { SortingCriteria::Filename, false };
auto media = ml->videoFiles( &params )->all();
ASSERT_EQ( 2u, media.size() );
ASSERT_EQ( m2->id(), media[0]->id() );
ASSERT_EQ( m1->id(), media[1]->id() );
params.desc = true;
media = ml->videoFiles( &params )->all();
ASSERT_EQ( 2u, media.size() );
ASSERT_EQ( m2->id(), media[1]->id() );
ASSERT_EQ( m1->id(), media[0]->id() );
}
TEST_F( Medias, SortByPostNumberFilename )
{
auto m0 = std::static_pointer_cast<Media>( ml->addMedia( "8ab0.mp3", Media::Type::Video ) );
m0->setTitle( "8ab0", false );
auto m1 = std::static_pointer_cast<Media>( ml->addMedia( "8ab1.mp3", Media::Type::Video ) );
m1->setTitle( "8ab1", false );
auto m2 = std::static_pointer_cast<Media>( ml->addMedia( "8ab10.mp3", Media::Type::Video ) );
m2->setTitle( "8ab10", false );
auto m3 = std::static_pointer_cast<Media>( ml->addMedia( "9ab1.mp3", Media::Type::Video ) );
m3->setTitle( "9ab1", false );
QueryParameters params { SortingCriteria::Filename, false };
auto media = ml->videoFiles( &params )->all();
ASSERT_EQ( 4u, media.size() );
ASSERT_EQ( m0->id(), media[0]->id() );
ASSERT_EQ( m1->id(), media[1]->id() );
ASSERT_EQ( m2->id(), media[2]->id() );
ASSERT_EQ( m3->id(), media[3]->id() );
params.desc = true;
media = ml->videoFiles( &params )->all();
ASSERT_EQ( 4u, media.size() );
ASSERT_EQ( m0->id(), media[3]->id() );
ASSERT_EQ( m1->id(), media[2]->id() );
ASSERT_EQ( m2->id(), media[1]->id() );
ASSERT_EQ( m3->id(), media[0]->id() );
}
TEST_F( Medias, SortByFilename )
{
auto m1 = std::static_pointer_cast<Media>( ml->addMedia( "zzzzz.mp3", Media::Type::Video ) );
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment