Ticket #12961: 0001-SortHelper-and-store-sort-fields-in-db.patch

File 0001-SortHelper-and-store-sort-fields-in-db.patch, 159.3 KB (added by David Hampton <mythtv@…>, 9 years ago)

New SortHelper class. Store sortable field in database.

  • mythplugins/mythnetvision/mythnetvision/netsearch.cpp

     .../mythnetvision/mythnetvision/netsearch.cpp      |   1 +
     .../mythnetvision/mythnetvision/nettree.cpp        |   6 +-
     mythtv/bindings/perl/MythTV.pm                     |   6 +-
     mythtv/bindings/php/MythBackend.php                |   6 +-
     mythtv/libs/libmyth/mythrssmanager.cpp             |   6 +-
     mythtv/libs/libmyth/netutils.cpp                   |  31 +-
     mythtv/libs/libmyth/programinfo.cpp                | 129 +++++++--
     mythtv/libs/libmyth/programinfo.h                  |  23 +-
     mythtv/libs/libmyth/rssparse.cpp                   |  13 +-
     mythtv/libs/libmyth/rssparse.h                     |   7 +-
     .../test/test_programinfo/test_programinfo.h       |  53 +++-
     mythtv/libs/libmythbase/libmythbase.pro            |   3 +
     mythtv/libs/libmythbase/mythsorthelper.cpp         |  92 ++++++
     mythtv/libs/libmythbase/mythsorthelper.h           |  30 ++
     mythtv/libs/libmythbase/mythversion.h              |   6 +-
     .../test/test_videometadata/test_videometadata.h   |  26 +-
     mythtv/libs/libmythmetadata/videometadata.cpp      | 320 +++++++++++----------
     mythtv/libs/libmythmetadata/videometadata.h        |  37 +--
     .../libmythmetadata/videometadatalistmanager.cpp   |  35 ++-
     .../libmythmetadata/videometadatalistmanager.h     |   3 +
     mythtv/libs/libmythmetadata/videoscan.cpp          |   8 +-
     mythtv/libs/libmythtv/datadirect.cpp               |  31 +-
     mythtv/libs/libmythtv/dbcheck.cpp                  | 146 +++++++++-
     mythtv/libs/libmythtv/eithelper.cpp                |   8 +-
     mythtv/libs/libmythtv/programdata.cpp              |  86 +++++-
     mythtv/libs/libmythtv/programdata.h                |  25 +-
     mythtv/libs/libmythtv/recordinginfo.cpp            |  37 ++-
     mythtv/libs/libmythtv/recordinginfo.h              |   4 +
     mythtv/libs/libmythtv/recordingrule.cpp            |  37 ++-
     mythtv/libs/libmythtv/recordingrule.h              |   2 +
     .../test/test_eitfixups/test_eitfixups.cpp         |   2 +
     mythtv/programs/mythbackend/main_helpers.cpp       |   5 +-
     mythtv/programs/mythbackend/scheduler.cpp          |  23 +-
     mythtv/programs/mythbackend/services/video.cpp     |   8 +-
     mythtv/programs/mythfrontend/globalsettings.cpp    |  38 +++
     mythtv/programs/mythfrontend/main.cpp              |   6 +-
     mythtv/programs/mythfrontend/playbackbox.cpp       |  11 +-
     mythtv/programs/mythfrontend/playbackbox.h         |   1 -
     mythtv/programs/mythfrontend/proglist.cpp          |  29 +-
     .../programs/mythfrontend/programrecpriority.cpp   |  77 +++--
     mythtv/programs/mythfrontend/videofilter.cpp       |  41 +--
     mythtv/programs/mythfrontend/videofilter.h         |   4 +-
     mythtv/programs/mythfrontend/videolist.cpp         |  53 +---
     mythtv/programs/mythpreviewgen/main.cpp            |   6 +-
     44 files changed, 1094 insertions(+), 427 deletions(-)
     create mode 100644 mythtv/libs/libmythbase/mythsorthelper.cpp
     create mode 100644 mythtv/libs/libmythbase/mythsorthelper.h
    
    diff --git a/mythplugins/mythnetvision/mythnetvision/netsearch.cpp b/mythplugins/mythnetvision/mythnetvision/netsearch.cpp
    index 5aa8ad5..e9e0014 100644
    a b void NetSearch::SlotItemChanged()  
    509509        MythUIButtonListItem *btn = m_siteList->GetItemCurrent();
    510510
    511511        ResultItem res(btn->GetText(), QString(), QString(),
     512                       QString(), QString(),
    512513                       QString(), QString(), QString(), QString(),
    513514                       QDateTime(), 0, 0, -1, QString(), QStringList(),
    514515                       QString(), QStringList(), 0, 0, QString(),
  • mythplugins/mythnetvision/mythnetvision/nettree.cpp

    diff --git a/mythplugins/mythnetvision/mythnetvision/nettree.cpp b/mythplugins/mythnetvision/mythnetvision/nettree.cpp
    index b140e8a..9027218 100644
    a b void NetTree::UpdateResultItem(ResultItem *item)  
    714714void NetTree::UpdateSiteItem(RSSSite *site)
    715715{
    716716    ResultItem res =
    717         ResultItem(site->GetTitle(), QString(), site->GetDescription(),
     717        ResultItem(site->GetTitle(), QString(), QString(), QString(),
     718                   site->GetDescription(),
    718719                   site->GetURL(), site->GetImage(), QString(),
    719720                   site->GetAuthor(), QDateTime(), 0, 0, -1, QString(),
    720721                   QStringList(), QString(), QStringList(), 0, 0, QString(),
    void NetTree::UpdateCurrentItem(void)  
    758759    }
    759760
    760761    ResultItem res =
    761         ResultItem(title, QString(), QString(), QString(), thumb, QString(),
     762        ResultItem(title, QString(), QString(), QString(), QString(),
     763                   QString(), thumb, QString(),
    762764                   QString(), QDateTime(), 0, 0, -1, QString(),
    763765                   QStringList(), QString(), QStringList(), 0, 0, QString(),
    764766                   0, QStringList(), 0, 0, 0);
  • mythtv/bindings/perl/MythTV.pm

    diff --git a/mythtv/bindings/perl/MythTV.pm b/mythtv/bindings/perl/MythTV.pm
    index 80ebd8f..eca6311 100644
    a b package MythTV;  
    107107# Note: as of July 21, 2010, this is actually a string, to account for proto
    108108# versions of the form "58a".  This will get used if protocol versions are
    109109# changed on a fixes branch ongoing.
    110     our $PROTO_VERSION = "91";
    111     our $PROTO_TOKEN = "BuzzOff";
     110    our $PROTO_VERSION = "92";
     111    our $PROTO_TOKEN = "LightSpeed";
    112112
    113113# currentDatabaseVersion is defined in libmythtv in
    114114# mythtv/libs/libmythtv/dbcheck.cpp and should be the current MythTV core
    package MythTV;  
    120120# NUMPROGRAMLINES is defined in mythtv/libs/libmythtv/programinfo.h and is
    121121# the number of items in a ProgramInfo QStringList group used by
    122122# ProgramInfo::ToSringList and ProgramInfo::FromStringList.
    123     our $NUMPROGRAMLINES = 52;
     123    our $NUMPROGRAMLINES = 54;
    124124
    125125# Reasons a recording wouldn't be happening (from libs/libmythtv/programinfo.h)
    126126    our %RecStatus_Types = (
  • mythtv/bindings/php/MythBackend.php

    diff --git a/mythtv/bindings/php/MythBackend.php b/mythtv/bindings/php/MythBackend.php
    index aba7bdf..4e43ebb 100644
    a b class MythBackend {  
    1111
    1212// MYTH_PROTO_VERSION is defined in libmyth in mythtv/libs/libmyth/mythcontext.h
    1313// and should be the current MythTV protocol version.
    14     static $protocol_version        = '91';
    15     static $protocol_token          = 'BuzzOff';
     14    static $protocol_version        = '92';
     15    static $protocol_token          = 'LightSpeed';
    1616
    1717// The character string used by the backend to separate records
    1818    static $backend_separator       = '[]:[]';
    class MythBackend {  
    2020// NUMPROGRAMLINES is defined in mythtv/libs/libmythtv/programinfo.h and is
    2121// the number of items in a ProgramInfo QStringList group used by
    2222// ProgramInfo::ToSringList and ProgramInfo::FromStringList.
    23     static $program_line_number     = 52;
     23    static $program_line_number     = 54;
    2424
    2525    private $fp                     = null;
    2626    private $connected              = false;
  • mythtv/libs/libmyth/mythrssmanager.cpp

    diff --git a/mythtv/libs/libmyth/mythrssmanager.cpp b/mythtv/libs/libmyth/mythrssmanager.cpp
    index 05a1248..cbbe0b8 100644
    a b void RSSSite::process(void)  
    233233        for (ResultItem::resultList::iterator i = items.begin();
    234234                i != items.end(); ++i)
    235235        {
    236             insertRSSArticle(new ResultItem((*i)->GetTitle(),
    237                QString(), (*i)->GetDescription(), (*i)->GetURL(),
     236            insertRSSArticle(new ResultItem(
     237               (*i)->GetTitle(), (*i)->GetSortTitle(),
     238               (*i)->GetSubtitle(), (*i)->GetSortSubtitle(),
     239               (*i)->GetDescription(), (*i)->GetURL(),
    238240               (*i)->GetThumbnail(), (*i)->GetMediaURL(),
    239241               (*i)->GetAuthor(), (*i)->GetDate(),
    240242               (*i)->GetTime(), (*i)->GetRating(),
  • mythtv/libs/libmyth/netutils.cpp

    diff --git a/mythtv/libs/libmyth/netutils.cpp b/mythtv/libs/libmyth/netutils.cpp
    index 7582171..5cc1b10 100644
    a b bool insertTreeArticleInDB(const QString &feedtitle, const QString &path,  
    404404                  " title, subtitle, description, url, type, thumbnail, mediaURL, author, "
    405405                  "date, time, rating, filesize, player, playerargs, download, "
    406406                  "downloadargs, width, height, language, podcast, downloadable, "
    407                   "customhtml, countries, season, episode) "
     407                  "customhtml, countries, season, episode, sorttitle, sortsubtitle) "
    408408            "VALUES( :FEEDTITLE, :PATH, :PATHTHUMB, :TITLE, :SUBTITLE, :DESCRIPTION, "
    409409            ":URL, :TYPE, :THUMBNAIL, :MEDIAURL, :AUTHOR, :DATE, :TIME, :RATING, "
    410410            ":FILESIZE, :PLAYER, :PLAYERARGS, :DOWNLOAD, :DOWNLOADARGS, :WIDTH, :HEIGHT, "
    411411            ":LANGUAGE, :PODCAST, :DOWNLOADABLE, :CUSTOMHTML, :COUNTRIES, :SEASON, "
    412             ":EPISODE);");
     412            ":EPISODE, :SORTTITLE, :SORTSUBTITLE);");
    413413    query.bindValue(":FEEDTITLE", feedtitle);
    414414    query.bindValue(":PATH", path);
    415415    query.bindValue(":PATHTHUMB", paththumb);
    416416    query.bindValue(":TITLE", item->GetTitle());
     417    query.bindValue(":SORTTITLE", item->GetSortTitle());
    417418    query.bindValue(":SUBTITLE", item->GetSubtitle().isNull() ? "" : item->GetSubtitle());
     419    query.bindValue(":SORTSUBTITLE", item->GetSortSubtitle().isNull() ? "" : item->GetSortSubtitle());
    418420    query.bindValue(":DESCRIPTION", item->GetDescription());
    419421    query.bindValue(":URL", item->GetURL());
    420422    query.bindValue(":TYPE", type);
    QMultiMap<QPair<QString,QString>, ResultItem*> getTreeArticles(const QString &fe  
    468470                  "rating, filesize, player, playerargs, download, "
    469471                  "downloadargs, width, height, language, "
    470472                  "downloadable, customhtml, countries, season, episode, "
    471                   "path, paththumb FROM internetcontentarticles "
     473                  "path, paththumb, sorttitle, sortsubtitle "
     474                  "FROM internetcontentarticles "
    472475                  "WHERE feedtitle = :FEEDTITLE AND podcast = 0 "
    473476                  "AND type = :TYPE ORDER BY title DESC;");
    474477    query.bindValue(":FEEDTITLE", feedtitle);
    QMultiMap<QPair<QString,QString>, ResultItem*> getTreeArticles(const QString &fe  
    482485    while (query.next())
    483486    {
    484487        QString     title = query.value(0).toString();
     488        QString     sortTitle = query.value(26).toString();
    485489        QString     subtitle = query.value(1).toString();
     490        QString     sortSubtitle = query.value(27).toString();
    486491        QString     desc = query.value(2).toString();
    487492        QString     URL = query.value(3).toString();
    488493        QString     type = query.value(4).toString();
    QMultiMap<QPair<QString,QString>, ResultItem*> getTreeArticles(const QString &fe  
    510515        QString     paththumb = query.value(25).toString();
    511516
    512517        QPair<QString,QString> pair(path,paththumb);
    513         ret.insert(pair, new ResultItem(title, subtitle, desc, URL,
     518        ret.insert(pair, new ResultItem(title, sortTitle, subtitle,
     519                   sortSubtitle, desc, URL,
    514520                   thumbnail, mediaURL, author, date, time, rating, filesize,
    515521                   player, playerargs, download, downloadargs,
    516522                   width, height, language, downloadable, countries,
    bool insertRSSArticleInDB(const QString &feedtitle, ResultItem *item,  
    741747                  "description, url, type, thumbnail, mediaURL, author, date, time, "
    742748                  "rating, filesize, player, playerargs, download, "
    743749                  "downloadargs, width, height, language, downloadable, countries, "
    744                   "podcast) "
     750                  "podcast, subtitle, sorttitle, sortsubtitle) "
    745751            "VALUES( :FEEDTITLE, :TITLE, :DESCRIPTION, :URL, :TYPE, :THUMBNAIL, "
    746752            ":MEDIAURL, :AUTHOR, :DATE, :TIME, :RATING, :FILESIZE, :PLAYER, "
    747753            ":PLAYERARGS, :DOWNLOAD, :DOWNLOADARGS, :WIDTH, :HEIGHT, "
    748             ":LANGUAGE, :DOWNLOADABLE, :COUNTRIES, :PODCAST);");
     754            ":LANGUAGE, :DOWNLOADABLE, :COUNTRIES, :PODCAST, "
     755            ":SUBTITLE, :SORTTITLE, :SORTSUBTITLE);");
    749756    query.bindValue(":FEEDTITLE", feedtitle);
    750757    query.bindValue(":TITLE", item->GetTitle());
     758    query.bindValue(":SORTTITLE", item->GetSortTitle());
     759    query.bindValue(":SUBTITLE", item->GetSubtitle());
     760    query.bindValue(":SORTSUBTITLE", item->GetSortSubtitle());
    751761    query.bindValue(":DESCRIPTION", item->GetDescription());
    752762    query.bindValue(":URL", item->GetURL());
    753763    query.bindValue(":TYPE", type);
    ResultItem::resultList getRSSArticles(const QString &feedtitle,  
    795805                  "thumbnail, mediaURL, author, date, time, "
    796806                  "rating, filesize, player, playerargs, download, "
    797807                  "downloadargs, width, height, language, "
    798                   "downloadable, countries, season, episode "
     808                  "downloadable, countries, season, episode, "
     809                  "sorttitle, subtitle, sortsubtitle "
    799810                  "FROM internetcontentarticles "
    800811                  "WHERE feedtitle = :FEEDTITLE AND podcast = 1 "
    801812                  "AND type = :TYPE ORDER BY date DESC;");
    ResultItem::resultList getRSSArticles(const QString &feedtitle,  
    809820    while (query.next())
    810821    {
    811822        QString     title = query.value(0).toString();
     823        QString     sortTitle = query.value(21).toString();
     824        QString     subtitle = query.value(22).toString();
     825        QString     sortSubtitle = query.value(23).toString();
    812826        QString     desc = query.value(1).toString();
    813827        QString     URL = query.value(2).toString();
    814828        QString     thumbnail = query.value(3).toString();
    ResultItem::resultList getRSSArticles(const QString &feedtitle,  
    830844        uint        season = query.value(19).toUInt();
    831845        uint        episode = query.value(20).toUInt();
    832846
    833         ret.append(new ResultItem(title, QString(), desc, URL, thumbnail,
     847        ret.append(new ResultItem(title, sortTitle, subtitle,
     848                   sortSubtitle, desc, URL, thumbnail,
    834849                   mediaURL, author, date, time, rating, filesize,
    835850                   player, playerargs, download, downloadargs,
    836851                   width, height, language, downloadable, countries,
  • mythtv/libs/libmyth/programinfo.cpp

    diff --git a/mythtv/libs/libmyth/programinfo.cpp b/mythtv/libs/libmyth/programinfo.cpp
    index d1f633b..ca861fd 100644
    a b using std::min;  
    3131#include "mythdb.h"
    3232#include "compat.h"
    3333#include "mythcdrom.h"
     34#include "mythsorthelper.h"
    3435
    3536#include <unistd.h> // for getpid()
    3637
    const QString ProgramInfo::kFromRecordedQuery =  
    8081    "       p.syndicatedepisodenumber, p.partnumber, p.parttotal,  "//48-50
    8182    "       p.season,           p.episode,      p.totalepisodes,   "//51-53
    8283    "       p.category_type,    r.recordedid,   r.inputname,       "//54-56
    83     "       r.bookmarkupdate                                       "//57-57
     84    "       r.bookmarkupdate,   r.sorttitle,    r.sortsubtitle     "//57-59
    8485    "FROM recorded AS r "
    8586    "LEFT JOIN channel AS c "
    8687    "ON (r.chanid    = c.chanid) "
    ProgramInfo::CategoryType string_to_myth_category_type(const QString &category_t  
    159160 */
    160161ProgramInfo::ProgramInfo(void) :
    161162    title(),
     163    sortTitle(),
    162164    subtitle(),
     165    sortSubtitle(),
    163166    description(),
    164167    season(0),
    165168    episode(0),
    ProgramInfo::ProgramInfo(void) :  
    232235    availableStatus(asAvailable),
    233236    spread(-1),
    234237    startCol(-1),
    235     sortTitle(),
    236238
    237239    // Private
    238240    inUseForWhat(),
    239241    positionMapDBReplacement(NULL)
    240242{
     243    ensureSortFields();
    241244}
    242245
    243246/** \fn ProgramInfo::ProgramInfo(const ProgramInfo &other)
    ProgramInfo::ProgramInfo(void) :  
    245248 */
    246249ProgramInfo::ProgramInfo(const ProgramInfo &other) :
    247250    title(other.title),
     251    sortTitle(other.sortTitle),
    248252    subtitle(other.subtitle),
     253    sortSubtitle(other.sortSubtitle),
    249254    description(other.description),
    250255    season(other.season),
    251256    episode(other.episode),
    ProgramInfo::ProgramInfo(const ProgramInfo &other) :  
    316321    availableStatus(other.availableStatus),
    317322    spread(other.spread),
    318323    startCol(other.startCol),
    319     sortTitle(other.sortTitle),
    320324
    321325    // Private
    322326    inUseForWhat(),
    323327    positionMapDBReplacement(other.positionMapDBReplacement)
    324328{
     329    ensureSortFields();
    325330}
    326331
    327332/** \fn ProgramInfo::ProgramInfo(uint _recordedid)
    ProgramInfo::ProgramInfo(uint _recordedid)  
    351356            .arg(_recordedid));
    352357        clear();
    353358    }
     359
     360    ensureSortFields();
    354361}
    355362
    356363/** \fn ProgramInfo::ProgramInfo(uint _chanid, const QDateTime &_recstartts)
    ProgramInfo::ProgramInfo(uint _chanid, const QDateTime &_recstartts) :  
    362369    clear();
    363370
    364371    LoadProgramFromRecorded(_chanid, _recstartts);
     372    ensureSortFields();
    365373}
    366374
    367375/** \fn ProgramInfo::ProgramInfo()
    ProgramInfo::ProgramInfo(uint _chanid, const QDateTime &_recstartts) :  
    370378ProgramInfo::ProgramInfo(
    371379    uint  _recordedid,
    372380    const QString &_title,
     381    const QString &_sortTitle,
    373382    const QString &_subtitle,
     383    const QString &_sortSubtitle,
    374384    const QString &_description,
    375385    uint  _season,
    376386    uint  _episode,
    ProgramInfo::ProgramInfo(  
    430440    const QString &_inputname,
    431441    const QDateTime &_bookmarkupdate) :
    432442    title(_title),
     443    sortTitle(_sortTitle),
    433444    subtitle(_subtitle),
     445    sortSubtitle(_sortSubtitle),
    434446    description(_description),
    435447    season(_season),
    436448    episode(_episode),
    ProgramInfo::ProgramInfo(  
    504516    availableStatus(asAvailable),
    505517    spread(-1),
    506518    startCol(-1),
    507     sortTitle(),
    508519
    509520    // Private
    510521    inUseForWhat(),
    ProgramInfo::ProgramInfo(  
    514525        originalAirDate = QDate();
    515526
    516527    SetPathname(_pathname);
     528    ensureSortFields();
    517529}
    518530
    519531/** \fn ProgramInfo::ProgramInfo()
    ProgramInfo::ProgramInfo(  
    521533 */
    522534ProgramInfo::ProgramInfo(
    523535    const QString &_title,
     536    const QString &_sortTitle,
    524537    const QString &_subtitle,
     538    const QString &_sortSubtitle,
    525539    const QString &_description,
    526540    uint  _season,
    527541    uint  _episode,
    ProgramInfo::ProgramInfo(  
    551565
    552566    bool duplicate) :
    553567    title(_title),
     568    sortTitle(_sortTitle),
    554569    subtitle(_subtitle),
     570    sortSubtitle(_sortSubtitle),
    555571    description(_description),
    556572    season(_season),
    557573    episode(_episode),
    ProgramInfo::ProgramInfo(  
    622638    availableStatus(asAvailable),
    623639    spread(-1),
    624640    startCol(-1),
    625     sortTitle(),
    626641
    627642    // Private
    628643    inUseForWhat(),
    629644    positionMapDBReplacement(NULL)
    630645{
     646    ensureSortFields();
    631647}
    632648
    633649/** \fn ProgramInfo::ProgramInfo()
    ProgramInfo::ProgramInfo(  
    635651 */
    636652ProgramInfo::ProgramInfo(
    637653    const QString &_title,
     654    const QString &_sortTitle,
    638655    const QString &_subtitle,
     656    const QString &_sortSubtitle,
    639657    const QString &_description,
    640658    const QString &_syndicatedepisode,
    641659    const QString &_category,
    ProgramInfo::ProgramInfo(  
    679697
    680698    const ProgramList &schedList) :
    681699    title(_title),
     700    sortTitle(_sortTitle),
    682701    subtitle(_subtitle),
     702    sortSubtitle(_sortSubtitle),
    683703    description(_description),
    684704    season(_season),
    685705    episode(_episode),
    ProgramInfo::ProgramInfo(  
    753773    availableStatus(asAvailable),
    754774    spread(-1),
    755775    startCol(-1),
    756     sortTitle(),
    757776
    758777    // Private
    759778    inUseForWhat(),
    ProgramInfo::ProgramInfo(  
    805824            s.recstatus == RecStatus::Failing)
    806825        recstatus = s.recstatus;
    807826    }
     827    ensureSortFields();
    808828}
    809829
    810830/** \fn ProgramInfo::ProgramInfo()
    ProgramInfo::ProgramInfo(  
    812832 */
    813833ProgramInfo::ProgramInfo(
    814834    const QString &_title,
     835    const QString &_sortTitle,
    815836    const QString &_subtitle,
     837    const QString &_sortSubtitle,
    816838    const QString &_description,
    817839    uint  _season,
    818840    uint  _episode,
    ProgramInfo::ProgramInfo(  
    837859    const QString &_programid,
    838860    const QString &_inetref) :
    839861    title(_title),
     862    sortTitle(_sortTitle),
    840863    subtitle(_subtitle),
     864    sortSubtitle(_sortSubtitle),
    841865    description(_description),
    842866    season(_season),
    843867    episode(_episode),
    ProgramInfo::ProgramInfo(  
    908932    availableStatus(asAvailable),
    909933    spread(-1),
    910934    startCol(-1),
    911     sortTitle(),
    912935
    913936    // Private
    914937    inUseForWhat(),
    915938    positionMapDBReplacement(NULL)
    916939{
     940    ensureSortFields();
    917941}
    918942
    919943/** \fn ProgramInfo::ProgramInfo(const QString &_pathname)
    ProgramInfo::ProgramInfo(const QString &_pathname) :  
    950974        SetPathname(QFileInfo(_pathname).absoluteFilePath());
    951975    else
    952976        SetPathname(_pathname);
     977    ensureSortFields();
    953978}
    954979
    955980/** \fn ProgramInfo::ProgramInfo()
    ProgramInfo::ProgramInfo(const QString &_pathname) :  
    958983ProgramInfo::ProgramInfo(const QString &_pathname,
    959984                         const QString &_plot,
    960985                         const QString &_title,
     986                         const QString &_sortTitle,
    961987                         const QString &_subtitle,
     988                         const QString &_sortSubtitle,
    962989                         const QString &_director,
    963990                         int _season, int _episode,
    964991                         const QString &_inetref,
    ProgramInfo::ProgramInfo(const QString &_pathname,  
    970997    clear();
    971998
    972999    title = _title;
     1000    sortTitle = _sortTitle;
    9731001    subtitle = _subtitle;
     1002    sortSubtitle = _sortSubtitle;
    9741003    description = _plot;
    9751004    season = _season;
    9761005    episode = _episode;
    ProgramInfo::ProgramInfo(const QString &_pathname,  
    9901019        pn = determineURLType(_pathname);
    9911020
    9921021    SetPathname(pn);
     1022    ensureSortFields();
    9931023}
    9941024
    9951025/** \fn ProgramInfo::ProgramInfo()
    ProgramInfo::ProgramInfo(const QString &_title, uint _chanid,  
    10341064
    10351065    description = title =
    10361066        QString("%1 (%2)").arg(title).arg(QObject::tr("Manual Record"));
     1067    ensureSortFields();
    10371068}
    10381069
    10391070/** \fn ProgramInfo::ProgramInfo()
    ProgramInfo::ProgramInfo(  
    10491080    category = _category;
    10501081    startts  = _startts;
    10511082    endts    = _endts;
     1083    ensureSortFields();
    10521084}
    10531085
    10541086
    void ProgramInfo::clone(const ProgramInfo &other,  
    10711103         startts == other.startts);
    10721104
    10731105    title = other.title;
     1106    sortTitle = other.sortTitle;
    10741107    subtitle = other.subtitle;
     1108    sortSubtitle = other.sortSubtitle;
    10751109    description = other.description;
    10761110    season = other.season;
    10771111    episode = other.episode;
    void ProgramInfo::clone(const ProgramInfo &other,  
    11481182    {
    11491183        spread = other.spread;
    11501184        startCol = other.startCol;
    1151         sortTitle = other.sortTitle;
    11521185        availableStatus = other.availableStatus;
    11531186
    11541187        inUseForWhat = other.inUseForWhat;
    void ProgramInfo::clone(const ProgramInfo &other,  
    11561189    }
    11571190
    11581191    title.detach();
     1192    sortTitle.detach();
    11591193    subtitle.detach();
     1194    sortSubtitle.detach();
    11601195    description.detach();
    11611196    category.detach();
    11621197
    void ProgramInfo::clone(const ProgramInfo &other,  
    11761211    programid.detach();
    11771212    inetref.detach();
    11781213
    1179     sortTitle.detach();
    11801214    inUseForWhat.detach();
    11811215    inputname.detach();
    11821216}
    void ProgramInfo::clone(const ProgramInfo &other,  
    11841218void ProgramInfo::clear(void)
    11851219{
    11861220    title.clear();
     1221    sortTitle.clear();
    11871222    subtitle.clear();
     1223    sortSubtitle.clear();
    11881224    description.clear();
    11891225    season = 0;
    11901226    episode = 0;
    void ProgramInfo::clear(void)  
    12161252    inetref.clear();
    12171253    catType = kCategoryNone;
    12181254
    1219     sortTitle.clear();
    1220 
    12211255    recpriority = 0;
    12221256
    12231257    filesize = 0ULL;
    void ProgramInfo::clear(void)  
    12661300    positionMapDBReplacement = NULL;
    12671301}
    12681302
     1303/** \fn ProgramInfo::ensureSortFields
     1304 *  \brief Ensure that the sortTitle and sortSubtitle fields are set.
     1305 */
     1306void ProgramInfo::ensureSortFields(void)
     1307{
     1308    SortHelper *sh = new SortHelper;
     1309
     1310    if (sortTitle.isEmpty() and !title.isEmpty())
     1311        sortTitle = sh->doTitle(title);
     1312    if (sortSubtitle.isEmpty() and !subtitle.isEmpty())
     1313        sortSubtitle = sh->doTitle(subtitle);
     1314}
     1315
    12691316/** \fn ProgramInfo::~ProgramInfo()
    12701317 *  \brief Destructor deletes "record" if it exists.
    12711318 */
    ProgramInfo::~ProgramInfo()  
    12731320{
    12741321}
    12751322
     1323void ProgramInfo::SetTitle(const QString &t, const QString &st)
     1324{
     1325    title = t;
     1326    title.detach();
     1327    sortTitle = st;
     1328    sortTitle.detach();
     1329}
     1330
     1331void ProgramInfo::SetTitle(const QString &t)
     1332{
     1333    SortHelper *sh = new SortHelper;
     1334    SetTitle(t, sh->doTitle(t));
     1335}
     1336
     1337void ProgramInfo::SetSubtitle(const QString &st, const QString &sst)
     1338{
     1339    subtitle = st;
     1340    subtitle.detach();
     1341    sortSubtitle = sst;
     1342    sortSubtitle.detach();
     1343}
     1344
     1345void ProgramInfo::SetSubtitle(const QString &st)
     1346{
     1347    SortHelper *sh = new SortHelper;
     1348    SetSubtitle(st, sh->doTitle(st));
     1349}
     1350
    12761351/// \brief Creates a unique string that can be used to identify a recording.
    12771352QString ProgramInfo::MakeUniqueKey(
    12781353    uint chanid, const QDateTime &recstartts)
    void ProgramInfo::ToStringList(QStringList &list) const  
    14371512    INT_TO_LIST(recordedid);          // 49
    14381513    STR_TO_LIST(inputname);           // 50
    14391514    DATETIME_TO_LIST(bookmarkupdate); // 51
     1515
     1516    STR_TO_LIST(sortTitle);        // 52
     1517    STR_TO_LIST(sortSubtitle);     // 53
    14401518/* do not forget to update the NUMPROGRAMLINES defines! */
    14411519}
    14421520
    bool ProgramInfo::FromStringList(QStringList::const_iterator &it,  
    15491627    STR_FROM_LIST(inputname);           // 50
    15501628    DATETIME_FROM_LIST(bookmarkupdate); // 51
    15511629
     1630    STR_FROM_LIST(sortTitle);           // 52
     1631    STR_FROM_LIST(sortSubtitle);        // 53
     1632
    15521633    if (!origChanid || !origRecstartts.isValid() ||
    15531634        (origChanid != chanid) || (origRecstartts != recstartts))
    15541635    {
    15551636        availableStatus = asAvailable;
    15561637        spread = -1;
    15571638        startCol = -1;
    1558         sortTitle = QString();
    15591639        inUseForWhat = QString();
    15601640        positionMapDBReplacement = NULL;
    15611641    }
    15621642
     1643    ensureSortFields();
     1644
    15631645    return true;
    15641646}
    15651647
    void ProgramInfo::ToMap(InfoMap &progMap,  
    15841666
    15851667    progMap["title"] = title;
    15861668    progMap["subtitle"] = subtitle;
     1669    progMap["sorttitle"] = sortTitle;
     1670    progMap["sortsubtitle"] = sortSubtitle;
    15871671
    15881672    QString tempSubTitle = title;
     1673    QString tempSortSubtitle = sortTitle;
    15891674    if (!subtitle.trimmed().isEmpty())
    15901675    {
    15911676        tempSubTitle = QString("%1 - \"%2\"")
    15921677            .arg(tempSubTitle).arg(subtitle);
     1678        tempSortSubtitle = QString("%1 - \"%2\"")
     1679            .arg(tempSortSubtitle).arg(sortSubtitle);
    15931680    }
    15941681
    15951682    progMap["titlesubtitle"] = tempSubTitle;
     1683    progMap["sorttitlesubtitle"] = tempSortSubtitle;
    15961684
    15971685    progMap["description"] = description;
    15981686
    bool ProgramInfo::LoadProgramFromRecorded(  
    20202108
    20212109        // everything below this line (in context) is not serialized
    20222110        spread = startCol = -1;
    2023         sortTitle.clear();
    20242111        availableStatus = asAvailable;
    20252112        inUseForWhat.clear();
    20262113        positionMapDBReplacement = NULL;
    20272114    }
    20282115
    20292116    title        = query.value(0).toString();
     2117    sortTitle    = query.value(58).toString();
    20302118    subtitle     = query.value(1).toString();
     2119    sortSubtitle = query.value(59).toString();
    20312120    description  = query.value(2).toString();
    20322121    season       = query.value(3).toUInt();
    20332122    if (season == 0)
    bool ProgramInfo::LoadProgramFromRecorded(  
    21512240    // Extra stuff which is not serialized and may get lost.
    21522241    /**/// spread
    21532242    /**/// startCol
    2154     /**/// sortTitle
    21552243    /**/// availableStatus
    21562244    /**/// inUseForWhat
    21572245    /**/// postitionMapDBReplacement
    void ProgramInfo::SubstituteMatches(QString &str)  
    53485436
    53495437    str.replace(QString("%FILE%"), GetBasename());
    53505438    str.replace(QString("%TITLE%"), title);
     5439    str.replace(QString("%SORTTITLE%"), sortTitle);
    53515440    str.replace(QString("%SUBTITLE%"), subtitle);
     5441    str.replace(QString("%SORTSUBTITLE%"), sortSubtitle);
    53525442    str.replace(QString("%SEASON%"), QString::number(season));
    53535443    str.replace(QString("%EPISODE%"), QString::number(episode));
    53545444    str.replace(QString("%TOTALEPISODES%"), QString::number(totalepisodes));
    static bool FromProgramQuery(const QString &sql, const MSqlBindings &bindings,  
    55035593        "oldrecstatus.findid, program.videoprop+0, program.audioprop+0, "
    55045594        "program.subtitletypes+0, program.syndicatedepisodenumber, "
    55055595        "program.partnumber, program.parttotal, "
    5506         "program.season, program.episode, program.totalepisodes ");
     5596        "program.season, program.episode, program.totalepisodes, "
     5597        "program.sorttitle, program.sortsubtitle ");
    55075598
    55085599    QString querystr = QString(
    55095600        "SELECT %1 "
    bool LoadFromProgram( ProgramList &destination,  
    56815772        destination.push_back(
    56825773            new ProgramInfo(
    56835774                query.value(3).toString(), // title
     5775                query.value(32).toString(), // sortTitle
    56845776                query.value(4).toString(), // subtitle
     5777                query.value(33).toString(), // sortSubtitle
    56855778                query.value(5).toString(), // description
    56865779                query.value(26).toString(), // syndicatedepisodenumber
    56875780                query.value(6).toString(), // category
    bool LoadFromOldRecorded(  
    57745867        "       title, subtitle, description, season, episode, category, seriesid, "
    57755868        "       programid, inetref, channel.channum, channel.callsign, "
    57765869        "       channel.name, findid, rectype, recstatus, recordid, "
    5777         "       duplicate "
     5870        "       duplicate, sorttitle, sortsubtitle "
    57785871        " FROM oldrecorded "
    57795872        " LEFT JOIN channel ON oldrecorded.chanid = channel.chanid "
    57805873        " WHERE oldrecorded.future = 0 "
    bool LoadFromOldRecorded(  
    58095902
    58105903        destination.push_back(new ProgramInfo(
    58115904            query.value(3).toString(),
     5905            query.value(20).toString(),
    58125906            query.value(4).toString(),
     5907            query.value(21).toString(),
    58135908            query.value(5).toString(),
    58145909            query.value(6).toUInt(),
    58155910            query.value(7).toUInt(),
    bool LoadFromRecorded(  
    59656060            new ProgramInfo(
    59666061                query.value(55).toUInt(),
    59676062                query.value(0).toString(),
     6063                query.value(58).toString(),
    59686064                query.value(1).toString(),
     6065                query.value(59).toString(),
    59696066                query.value(2).toString(),
    59706067                season,
    59716068                episode,
  • mythtv/libs/libmyth/programinfo.h

    diff --git a/mythtv/libs/libmyth/programinfo.h b/mythtv/libs/libmyth/programinfo.h
    index 63eac7a..279e24d 100644
    a b  
    2424   in mythversion.h need to be bumped, and also follow the instructions in
    2525   myth_version.h about other changes needed when the network protocol changes.
    2626*/
    27 #define NUMPROGRAMLINES 52
     27#define NUMPROGRAMLINES 54
    2828
    2929class ProgramInfo;
    3030typedef AutoDeleteDeque<ProgramInfo*> ProgramList;
    class MPUBLIC ProgramInfo  
    8181    /// Constructs a ProgramInfo from data in 'recorded' table
    8282    ProgramInfo(uint recordedid,
    8383                const QString &title,
     84                const QString &sortTitle,
    8485                const QString &subtitle,
     86                const QString &sortSubtitle,
    8587                const QString &description,
    8688                uint season,
    8789                uint episode,
    class MPUBLIC ProgramInfo  
    144146
    145147    /// Constructs a ProgramInfo from data in 'oldrecorded' table
    146148    ProgramInfo(const QString &title,
     149                const QString &sortTitle,
    147150                const QString &subtitle,
     151                const QString &sortSubtitle,
    148152                const QString &description,
    149153                uint season,
    150154                uint episode,
    class MPUBLIC ProgramInfo  
    176180
    177181    /// Constructs a ProgramInfo from listings data in 'program' table
    178182    ProgramInfo(const QString &title,
     183                const QString &sortTitle,
    179184                const QString &subtitle,
     185                const QString &sortSubtitle,
    180186                const QString &description,
    181187                const QString &syndicatedepisode,
    182188                const QString &category,
    class MPUBLIC ProgramInfo  
    220226                const ProgramList &schedList);
    221227    /// Constructs a basic ProgramInfo (used by RecordingInfo)
    222228    ProgramInfo(const QString &title,
     229                const QString &sortTitle,
    223230                const QString &subtitle,
     231                const QString &sortSubtitle,
    224232                const QString &description,
    225233                uint season,
    226234                uint episode,
    class MPUBLIC ProgramInfo  
    250258    ProgramInfo(const QString &pathname,
    251259                const QString &plot,
    252260                const QString &title,
     261                const QString &sortTitle,
    253262                const QString &subtitle,
     263                const QString &sortSubtitle,
    254264                const QString &director,
    255265                int season, int episode,
    256266                const QString &inetref,
    class MPUBLIC ProgramInfo  
    283293    ProgramInfo &operator=(const ProgramInfo &other);
    284294    virtual void clone(const ProgramInfo &other,
    285295                       bool ignore_non_serialized_data = false);
     296    virtual void ensureSortFields(void);
    286297
    287298    virtual void clear(void);
    288299
    class MPUBLIC ProgramInfo  
    340351    bool IsFileReadable(void) const;
    341352
    342353    QString GetTitle(void)        const { return title; }
     354    QString GetSortTitle(void)    const { return sortTitle; }
    343355    QString GetSubtitle(void)     const { return subtitle; }
     356    QString GetSortSubtitle(void) const { return sortSubtitle; }
    344357    QString GetDescription(void)  const { return description; }
    345358    uint    GetSeason(void)       const { return season; }
    346359    uint    GetEpisode(void)      const { return episode; }
    class MPUBLIC ProgramInfo  
    482495                     QString grp = "\"") const;
    483496
    484497    // Quick sets
    485     void SetTitle(const QString &t) { title = t; title.detach(); }
     498    void SetTitle(const QString &t, const QString &st);
     499    void SetTitle(const QString &t);
     500    void SetSubtitle(const QString &st, const QString &sst);
     501    void SetSubtitle(const QString &st);
    486502    void SetProgramInfoType(ProgramInfoType t)
    487503        { programflags &= ~FL_TYPEMASK; programflags |= ((uint32_t)t<<20); }
    488504    void SetPathname(const QString&) const;
    class MPUBLIC ProgramInfo  
    715731
    716732  protected:
    717733    QString title;
     734    QString sortTitle;
    718735    QString subtitle;
     736    QString sortSubtitle;
    719737    QString description;
    720738    uint    season;
    721739    uint    episode;
    class MPUBLIC ProgramInfo  
    790808        { return (AvailableStatusType) availableStatus; }
    791809    int8_t spread;   // only used in guidegrid.cpp
    792810    int8_t startCol; // only used in guidegrid.cpp
    793     QString sortTitle; // only use for sorting in frontend
    794811
    795812    static const QString kFromRecordedQuery;
    796813
  • mythtv/libs/libmyth/rssparse.cpp

    diff --git a/mythtv/libs/libmyth/rssparse.cpp b/mythtv/libs/libmyth/rssparse.cpp
    index 1db242a..4b16a61 100644
    a b  
    1313#include "mythdirs.h"
    1414#include "mythdate.h"
    1515#include "programinfo.h" // for format_season_and_episode()
     16#include "mythsorthelper.h"
    1617
    1718using namespace std;
    1819
    19 ResultItem::ResultItem(const QString& title, const QString& subtitle,
     20ResultItem::ResultItem(const QString& title, const QString& sortTitle,
     21              const QString& subtitle, const QString& sortSubtitle,
    2022              const QString& desc, const QString& URL,
    2123              const QString& thumbnail, const QString& mediaURL,
    2224              const QString& author, const QDateTime& date,
    ResultItem::ResultItem(const QString& title, const QString& subtitle,  
    2931              const uint& season, const uint& episode,
    3032              const bool& customhtml)
    3133{
     34    SortHelper *sh = new SortHelper;
     35
    3236    m_title = title;
     37    m_sorttitle = sortTitle.isEmpty() ? sh->doTitle(title) : sortTitle;
    3338    m_subtitle = subtitle;
     39    m_sortsubtitle =
     40        sortSubtitle.isEmpty() ? sh->doTitle(subtitle) : sortSubtitle;
    3441    m_desc = desc;
    3542    m_URL = URL;
    3643    m_thumbnail = thumbnail;
    ResultItem::~ResultItem()  
    7077void ResultItem::toMap(InfoMap &metadataMap)
    7178{
    7279    metadataMap["title"] = m_title;
     80    metadataMap["sorttitle"] = m_sorttitle;
    7381    metadataMap["subtitle"] = m_subtitle;
     82    metadataMap["sortsubtitle"] = m_sortsubtitle;
    7483    metadataMap["description"] = m_desc;
    7584    metadataMap["url"] = m_URL;
    7685    metadataMap["thumbnail"] = m_thumbnail;
    ResultItem* Parse::ParseItem(const QDomElement& item) const  
    929938    if (mediaURL.isNull() || mediaURL == url)
    930939        downloadable = false;
    931940
    932     return(new ResultItem(title, subtitle, description,
     941    return(new ResultItem(title, QString(), subtitle, QString(), description,
    933942              url, thumbnail, mediaURL, author, date, duration,
    934943              rating, filesize, player, playerargs,
    935944              download, downloadargs, width, height,
  • mythtv/libs/libmyth/rssparse.h

    diff --git a/mythtv/libs/libmyth/rssparse.h b/mythtv/libs/libmyth/rssparse.h
    index 0a35dcf..0065b68 100644
    a b class MPUBLIC ResultItem  
    114114    typedef QList<ResultItem *> resultList;
    115115    typedef std::vector<ResultItem> List;
    116116
    117     ResultItem(const QString& title, const QString& subtitle,
     117    ResultItem(const QString& title, const QString& sortTitle,
     118              const QString& subtitle, const QString& sortSubtitle,
    118119              const QString& desc, const QString& URL,
    119120              const QString& thumbnail, const QString& mediaURL,
    120121              const QString& author, const QDateTime& date, const QString& time,
    class MPUBLIC ResultItem  
    130131    void toMap(InfoMap &infoMap);
    131132
    132133    const QString& GetTitle() const { return m_title; }
     134    const QString& GetSortTitle() const { return m_sorttitle; }
    133135    const QString& GetSubtitle() const { return m_subtitle; }
     136    const QString& GetSortSubtitle() const { return m_sortsubtitle; }
    134137    const QString& GetDescription() const { return m_desc; }
    135138    const QString& GetURL() const { return m_URL; }
    136139    const QString& GetThumbnail() const { return m_thumbnail; }
    class MPUBLIC ResultItem  
    155158
    156159  private:
    157160    QString      m_title;
     161    QString      m_sorttitle;
    158162    QString      m_subtitle;
     163    QString      m_sortsubtitle;
    159164    QString      m_desc;
    160165    QString      m_URL;
    161166    QString      m_thumbnail;
  • mythtv/libs/libmyth/test/test_programinfo/test_programinfo.h

    diff --git a/mythtv/libs/libmyth/test/test_programinfo/test_programinfo.h b/mythtv/libs/libmyth/test/test_programinfo/test_programinfo.h
    index 0298e99..85a798b 100644
    a b class TestProgramInfo : public QObject  
    3737    {
    3838        return ProgramInfo (
    3939            title,          /* title */
     40            "",              /* sortTitle */
    4041            "",              /* subtitle */
     42            "",              /* sortSubtitle */
    4143            "Its a movie.", /* description */
    4244            "", /* syndicated episode */
    4345            "", /* category */
    class TestProgramInfo : public QObject  
    8385        ProgramInfo program (
    8486            "/pathname",
    8587             "The plot",
    86              "The Title",
    87              "The Subtitle",
     88             "The Title", "title, the",
     89             "The Subtitle", "subtitle, the",
    8890             "Director",
    8991             1,
    9092             2,
    class TestProgramInfo : public QObject  
    142144        ProgramInfo programH (mockMovie ("", "", "Gone", 2012));
    143145        QVERIFY (programG.IsSameProgram (programH));
    144146    }
     147
     148    void programSorting_test(void)
     149    {
     150        ProgramInfo flash34
     151            (715,
     152             "The Flash (2014)", QString(),
     153             "The New Rogues", QString(),
     154             "Barry continues to train Jesse ...",
     155             3, 4, 23, "syndicatedepisode", "Drama",
     156             1514, "514", "WNUVDT", "WNUBDT (WNUV-DT)", "",
     157             QString("Default"), QString("Default"),
     158             "/recordings/1514_20161025235800.ts",
     159             "localhost", "Default",
     160             "EP01922936", "EP019229360055", "ttvdb.py_279121",
     161             ProgramInfo::kCategoryTVShow, 0, 6056109800,
     162             MythDate::fromString("2016-10-25 23:58:00"),
     163             MythDate::fromString("2016-10-26 01:02:00"),
     164             MythDate::fromString("2016-10-25 23:58:00"),
     165             MythDate::fromString("2016-10-26 01:02:00"),
     166             0.0, 2016, 0, 0, QDate(2016,10,25),
     167             QDateTime(QDate(2016,10,26),QTime(1,12,34)),
     168             RecStatus::Unknown, 0,
     169             kDupsInAll, kDupCheckSubThenDesc,
     170             0, 0, 0, 0, 0, "Prime A-1",
     171             QDateTime(QDate(0,0,0),QTime(0,0,0)));
     172        ProgramInfo supergirl23
     173            ("Supergirl", QString(),
     174             "Welcome to Earth", QString(),
     175             "An attack is made on the President as hot-button...",
     176             2, 3, 23, "Drama",
     177             1514, "514", "WNUVDT", "WNUBDT (WNUV-DT)", "",
     178             QString("Default"), QString("Default"),
     179             MythDate::fromString("2016-10-24 23:58:00"),
     180             MythDate::fromString("2016-10-25 01:02:00"),
     181             MythDate::fromString("2016-10-24 23:58:00"),
     182             MythDate::fromString("2016-10-25 01:02:00"),
     183             "295759", "5772362", "");
     184
     185        QCOMPARE (flash34.GetSortTitle(), QString("flash (2014)"));
     186        QCOMPARE (flash34.GetSortSubtitle(), QString("new rogues"));
     187        QVERIFY (flash34.GetSortTitle() < supergirl23.GetSortTitle());
     188        QString foo = "%TITLE%|%SORTTITLE%|%SUBTITLE%|%SORTSUBTITLE%";
     189        // Fake out GetPlaybackURL() so it doesn't attempt a database query
     190        flash34.SetProgramInfoType(kProgramInfoTypeVideoBD);
     191        flash34.SubstituteMatches(foo);
     192        QCOMPARE(foo, QString("The Flash (2014)|flash (2014)|The New Rogues|new rogues"));
     193    }
    145194};
  • mythtv/libs/libmythbase/libmythbase.pro

    diff --git a/mythtv/libs/libmythbase/libmythbase.pro b/mythtv/libs/libmythbase/libmythbase.pro
    index aa7ac15..efe32ea 100644
    a b HEADERS += threadedfilewriter.h mythsingledownload.h codecutil.h  
    3434HEADERS += mythsession.h
    3535HEADERS += ../../external/qjsonwrapper/qjsonwrapper/Json.h
    3636HEADERS += cleanupguard.h portchecker.h
     37HEADERS += mythsorthelper.h
    3738
    3839SOURCES += mthread.cpp mthreadpool.cpp
    3940SOURCES += mythsocket.cpp
    SOURCES += threadedfilewriter.cpp mythsingledownload.cpp codecutil.cpp  
    5556SOURCES += mythsession.cpp
    5657SOURCES += ../../external/qjsonwrapper/qjsonwrapper/Json.cpp
    5758SOURCES += cleanupguard.cpp portchecker.cpp
     59SOURCES += mythsorthelper.cpp
    5860
    5961unix {
    6062    SOURCES += mythsystemunix.cpp
    inc.files += plist.h bswap.h signalhandling.h ffmpeg-mmx.h mythdate.h  
    8486inc.files += mythplugin.h mythpluginapi.h mythqtcompat.h
    8587inc.files += remotefile.h mythsystemlegacy.h mythtypes.h
    8688inc.files += threadedfilewriter.h mythsingledownload.h mythsession.h
     89inc.files += mythsorthelper.h
    8790
    8891# Allow both #include <blah.h> and #include <libmythbase/blah.h>
    8992inc2.path  = $${PREFIX}/include/mythtv/libmythbase
  • new file mythtv/libs/libmythbase/mythsorthelper.cpp

    diff --git a/mythtv/libs/libmythbase/mythsorthelper.cpp b/mythtv/libs/libmythbase/mythsorthelper.cpp
    new file mode 100644
    index 0000000..4a81a9a
    - +  
     1// -*- Mode: c++ -*-
     2// vim: set expandtab tabstop=4 shiftwidth=4
     3
     4#include "mythsorthelper.h"
     5#include "mythcorecontext.h"
     6
     7/** \fn SortHelper::SortHelper
     8 *  \brief Create the object and read settings from the core context.
     9 *
     10 *  Create the object and read settings from the core context. Set of
     11 *  the various regular expressions and exclusion lists for later
     12 *  usage.
     13 *
     14 *  Handling the case where the gCoreContext object doesn't exists
     15 *  (i.e. running under the Qt test harness) allows this code and
     16 *  objects using it to be tested.
     17 */
     18SortHelper::SortHelper()
     19{
     20    QString excludes;
     21    QString prefixes(tr("^(The |A |An )",
     22                        "Regular Expression for what to ignore when sorting"));
     23    if (gCoreContext) {
     24        // Running code
     25        m_ignore_case = gCoreContext->GetNumSetting("SortIgnoreCase", true);
     26        m_ignore_prefixes = gCoreContext->GetNumSetting("SortIgnorePrefixes", true);
     27        excludes = gCoreContext->GetSetting("SortIgnorePrefixExceptions", "");
     28    } else {
     29        // Qt Test Harness
     30        m_ignore_case = true;
     31        m_ignore_prefixes = true;
     32        excludes = "A to Z";
     33    }
     34    if (m_ignore_case)
     35    {
     36        prefixes = prefixes.toLower();
     37        excludes = excludes.toLower();
     38    }
     39    m_ign_regex1 = QRegExp(prefixes);
     40    m_ign_regex2 = QRegExp(prefixes.replace("^","/"));
     41    m_excl_list = excludes.split(";", QString::SkipEmptyParts);
     42    for (int i = 0; i < m_excl_list.size(); i++)
     43      m_excl_list[i] = m_excl_list[i].trimmed();
     44    m_creator = "unknown";
     45}
     46
     47
     48/** \fn SortHelper::doTitle(QString)
     49 *  \brief Create the sortable form of an title string.
     50 *
     51 *  This function converts a title string to a version that can be
     52 *  used for sorting. Depending upon user settings, it may ignore the
     53 *  case of the string (by forcing all strings to lower case) and may
     54 *  strip the common prefix words "A", "An" and "The" from the
     55 *  beginning of the string.
     56 *
     57 * \param title The title of an item.
     58 * \return The conversion of the title to use when sorting.
     59 */
     60QString SortHelper::doTitle(QString title) const
     61{
     62    if (m_ignore_case)
     63        title = title.toLower();
     64    if (not m_ignore_prefixes)
     65        return title;
     66    if (m_excl_list.contains(title))
     67        return title;
     68    return title.remove(m_ign_regex1);
     69}
     70
     71/** \fn SortHelper::doPathname(QString)
     72 *  \brief Create the sortable form of an item.
     73 *
     74 *  This function converts a pathname to a version that can be used
     75 *  for sorting. Depending upon user settings, it may ignore the case
     76 *  of the string (by forcing all strings to lower case) and may strip
     77 *  the common prefix words "A", "An" and "The" from the beginning of
     78 *  each component in the pathname.
     79 *
     80 * \param title The pathname of an item.
     81 * \return The conversion of the pathname to use when sorting.
     82 */
     83QString SortHelper::doPathname(QString pathname) const
     84{
     85    if (m_ignore_case)
     86        pathname = pathname.toLower();
     87    if (not m_ignore_prefixes)
     88        return pathname;
     89    if (m_excl_list.contains(pathname))
     90        return pathname;
     91    return pathname.remove(m_ign_regex1).replace(m_ign_regex2, "/");
     92}
  • new file mythtv/libs/libmythbase/mythsorthelper.h

    diff --git a/mythtv/libs/libmythbase/mythsorthelper.h b/mythtv/libs/libmythbase/mythsorthelper.h
    new file mode 100644
    index 0000000..496b043
    - +  
     1// -*- Mode: c++ -*-
     2// vim: set expandtab tabstop=4 shiftwidth=4
     3
     4#ifndef MYTHSORTHELPER_H_
     5#define MYTHSORTHELPER_H_
     6
     7#include <QCoreApplication>
     8#include "mythbaseexp.h"
     9
     10class MBASE_PUBLIC SortHelper
     11{
     12    Q_DECLARE_TR_FUNCTIONS(SortHelper)
     13
     14  public:
     15    SortHelper();
     16    QString doTitle(QString title) const;
     17    QString doPathname(QString filename) const;
     18
     19  private:
     20    bool m_ignore_case;
     21
     22    bool m_ignore_prefixes;
     23    QRegExp m_ign_regex1;       // Anchored at the start
     24    QRegExp m_ign_regex2;       // Following a '/'
     25
     26    QStringList m_excl_list;
     27    QString m_creator;
     28};
     29
     30#endif // MYTHSORTHELPER_H_
  • mythtv/libs/libmythbase/mythversion.h

    diff --git a/mythtv/libs/libmythbase/mythversion.h b/mythtv/libs/libmythbase/mythversion.h
    index 9f0efb7..6a1753d 100644
    a b  
    4444 *       http://www.mythtv.org/wiki/Category:Myth_Protocol_Commands
    4545 *       http://www.mythtv.org/wiki/Category:Myth_Protocol
    4646 */
    47 #define MYTH_PROTO_VERSION "91"
    48 #define MYTH_PROTO_TOKEN "BuzzOff"
     47#define MYTH_PROTO_VERSION "92"
     48#define MYTH_PROTO_TOKEN "LightSpeed"
    4949
    5050/** \brief Increment this whenever the MythTV core database schema changes.
    5151 *
     
    6464 *      mythtv/bindings/php/MythBackend.php
    6565 */
    6666
    67 #define MYTH_DATABASE_VERSION "1346"
     67#define MYTH_DATABASE_VERSION "1347"
    6868
    6969
    7070 MBASE_PUBLIC  const char *GetMythSourceVersion();
  • mythtv/libs/libmythmetadata/test/test_videometadata/test_videometadata.h

    diff --git a/mythtv/libs/libmythmetadata/test/test_videometadata/test_videometadata.h b/mythtv/libs/libmythmetadata/test/test_videometadata/test_videometadata.h
    index 8f4f493..ce36d9e 100644
    a b class Testvideometadata: public QObject  
    345345    void ProgramWithInetref ()
    346346    {
    347347        MSKIP ("Might connect to the database or call the installed metadata grabbers.");
    348         ProgramInfo proginfo = ProgramInfo ("", "", "Test Movie", "", "", 0, 0, "tmdb3.py_1234", 0, 0, "");
     348        ProgramInfo proginfo = ProgramInfo ("", "", "Test Movie", "", "", "",
     349                                            "", 0, 0, "tmdb3.py_1234", 0, 0, "");
    349350        RecordingInfo recinfo = proginfo;
    350351        QCOMPARE (recinfo.GetInetRef(), QString("tmdb3.py_1234"));
    351352        QCOMPARE (GuessLookupType (&recinfo), kProbableMovie);
    352353
    353         proginfo = ProgramInfo ("", "", "Test Series", "Test Episode", "", 1, 15, "ttvdb.py_1234", 0, 0, "");
     354        proginfo = ProgramInfo ("", "", "Test Series", "", "Test Episode", "",
     355                                "", 1, 15, "ttvdb.py_1234", 0, 0, "");
    354356        recinfo = proginfo;
    355357        QCOMPARE (recinfo.GetInetRef(), QString("ttvdb.py_1234"));
    356358        QCOMPARE (GuessLookupType (&recinfo), kProbableTelevision);
    class Testvideometadata: public QObject  
    358360        //QCOMPARE (GuessLookupType (QString ("tmdb3.py_1234")), kProbableMovie);
    359361        //QCOMPARE (GuessLookupType (QString ("ttvdb.py_1234")), kProbableTelevision);
    360362    }
     363
     364    void testEmbeddedFilnameToMetadata ()
     365    {
     366        MSKIP ("Tries to connect to the database.");
     367        VideoMetadata obj = VideoMetadata(QString ("Series Title/Season 1/02x03 Episode Title.mp4"));
     368        QCOMPARE (obj.GetTitle(), QString ("Series Title"));
     369        QCOMPARE (obj.GetSortTitle(), QString ("series title"));
     370        QCOMPARE (obj.GetSubtitle(), QString ("Episode Title"));
     371        QCOMPARE (obj.GetSortSubtitle(), QString ("episode title"));
     372        QCOMPARE (obj.GetSeason(), 2);
     373        QCOMPARE (obj.GetEpisode(), 3);
     374
     375        obj = VideoMetadata(QString ("The Series Title/Season 1/02x03 The Episode Title.mp4"));
     376        QCOMPARE (obj.GetTitle(), QString ("The Series Title"));
     377        QCOMPARE (obj.GetSortTitle(), QString ("series title"));
     378        QCOMPARE (obj.GetSubtitle(), QString ("The Episode Title"));
     379        QCOMPARE (obj.GetSortSubtitle(), QString ("episode title"));
     380        QCOMPARE (obj.GetSeason(), 2);
     381        QCOMPARE (obj.GetEpisode(), 3);
     382    }
    361383};
  • mythtv/libs/libmythmetadata/videometadata.cpp

    diff --git a/mythtv/libs/libmythmetadata/videometadata.cpp b/mythtv/libs/libmythmetadata/videometadata.cpp
    index 8f4c2b4..dbf41fe 100644
    a b  
    1919#include "videometadatalistmanager.h"
    2020#include "videoutils.h"
    2121#include "programinfo.h" // for format_season_and_episode
     22#include "mythsorthelper.h"
    2223
    2324using namespace std;
    2425
    25 struct SortData
    26 {
    27     SortData(const QString &title, const QString &filename, const QString &id) :
    28         m_title(title), m_filename(filename), m_id(id)
    29     {
    30     }
    31 
    32     QString m_title;
    33     QString m_filename;
    34     QString m_id;
    35 };
    36 
    37 static bool operator<(const SortData &lhs, const SortData &rhs)
    38 {
    39     int ret = naturalCompare(lhs.m_title, rhs.m_title);
    40 
    41     if (ret == 0)
    42         ret = naturalCompare(lhs.m_filename, rhs.m_filename);
    43 
    44     if (ret == 0)
    45         ret = naturalCompare(lhs.m_id, rhs.m_id);
    46 
    47     return ret < 0;
    48 }
    49 
    50 VideoMetadata::SortKey::SortKey() : m_sd(NULL)
    51 {
    52 }
    53 
    54 VideoMetadata::SortKey::SortKey(const SortData &data)
    55 {
    56     m_sd = new SortData(data);
    57 }
    58 
    59 VideoMetadata::SortKey::SortKey(const SortKey &other) : m_sd(NULL)
    60 {
    61     *this = other;
    62 }
    63 
    64 VideoMetadata::SortKey &VideoMetadata::SortKey::operator=(const SortKey &rhs)
    65 {
    66     if (this != &rhs)
    67     {
    68         Clear();
    69         if (rhs.m_sd)
    70             m_sd = new SortData(*rhs.m_sd);
    71     }
    72 
    73     return *this;
    74 }
    75 
    76 VideoMetadata::SortKey::~SortKey()
    77 {
    78     Clear();
    79 }
    80 
    81 bool VideoMetadata::SortKey::isSet() const
    82 {
    83     return m_sd != 0;
    84 }
    85 
    86 void VideoMetadata::SortKey::Clear()
    87 {
    88     delete m_sd;
    89     m_sd = 0;
    90 }
    91 
    9226class VideoMetadataImp
    9327{
    9428  public:
    class VideoMetadataImp  
    9731    typedef VideoMetadata::cast_list cast_list;
    9832
    9933  public:
    100     VideoMetadataImp(const QString &filename, const QString &hash, const QString &trailer,
     34    VideoMetadataImp(const QString &filename, const QString &sortFilename,
     35             const QString &hash, const QString &trailer,
    10136             const QString &coverfile, const QString &screenshot, const QString &banner,
    102              const QString &fanart, const QString &title, const QString &subtitle,
     37             const QString &fanart, const QString &title, const QString &sortTitle,
     38             const QString &subtitle, const QString &sortSubtitle,
    10339             const QString &tagline, int year, const QDate &releasedate,
    10440             const QString &inetref, int collectionref, const QString &homepage,
    10541             const QString &director, const QString &studio,
    class VideoMetadataImp  
    11551             const QString &host = "",
    11652             bool processed = false,
    11753             VideoContentType contenttype = kContentUnknown) :
    118         m_title(title), m_subtitle(subtitle), m_tagline(tagline),
     54        m_title(title), m_sortTitle(sortTitle), m_subtitle(subtitle),
     55        m_sortSubtitle(sortSubtitle), m_tagline(tagline),
    11956        m_inetref(inetref), m_collectionref(collectionref), m_homepage(homepage),
    12057        m_director(director), m_studio(studio),
    12158        m_plot(plot), m_rating(rating), m_playcommand(playcommand), m_category(category),
    12259        m_genres(genres), m_countries(countries), m_cast(cast),
    123         m_filename(filename), m_hash(hash), m_trailer(trailer), m_coverfile(coverfile),
     60        m_filename(filename), m_sortFilename(sortFilename), m_hash(hash),
     61        m_trailer(trailer), m_coverfile(coverfile),
    12462        m_screenshot(screenshot), m_banner(banner), m_fanart(fanart),
    12563        m_host(host), m_categoryID(categoryID), m_childID(childID),
    12664        m_year(year), m_releasedate(releasedate), m_length(length), m_playcount(playcount),
    class VideoMetadataImp  
    12967        m_userrating(userrating), m_processed(processed),
    13068        m_contenttype(contenttype)
    13169    {
     70        // Try to glean data if none provided.
     71        if (title.isEmpty() and subtitle.isEmpty()
     72            and season == 0 and episode == 0)
     73        {
     74            m_title = VideoMetadata::FilenameToMeta(m_filename, 1);
     75            m_subtitle = VideoMetadata::FilenameToMeta(m_filename, 4);
     76            m_season = VideoMetadata::FilenameToMeta(m_filename, 2).toInt();
     77            m_episode = VideoMetadata::FilenameToMeta(m_filename, 3).toInt();
     78        }
     79
     80        SortHelper *sh = new SortHelper;
     81        if (m_sortFilename.isEmpty())
     82            m_sortFilename = sh->doPathname(m_filename);
     83        if (m_sortTitle.isEmpty())
     84            m_sortTitle = sh->doTitle(m_title);
     85        if (m_sortSubtitle.isEmpty())
     86            m_sortSubtitle = sh->doTitle(m_subtitle);
     87
    13288        VideoCategory::GetCategory().get(m_categoryID, m_category);
    13389    }
    13490
    class VideoMetadataImp  
    147103        if (this != &rhs)
    148104        {
    149105            m_title = rhs.m_title;
     106            m_sortTitle = rhs.m_sortTitle;
    150107            m_subtitle = rhs.m_subtitle;
     108            m_sortSubtitle = rhs.m_sortSubtitle;
    151109            m_tagline = rhs.m_tagline;
    152110            m_inetref = rhs.m_inetref;
    153111            m_collectionref = rhs.m_collectionref;
    class VideoMetadataImp  
    162120            m_countries = rhs.m_countries;
    163121            m_cast = rhs.m_cast;
    164122            m_filename = rhs.m_filename;
     123            m_sortFilename = rhs.m_sortFilename;
    165124            m_hash = rhs.m_hash;
    166125            m_trailer = rhs.m_trailer;
    167126            m_coverfile = rhs.m_coverfile;
    class VideoMetadataImp  
    188147            m_contenttype = rhs.m_contenttype;
    189148
    190149            // No DB vars
    191             m_sort_key = rhs.m_sort_key;
    192150            m_prefix = rhs.m_prefix;
    193151        }
    194152
    class VideoMetadataImp  
    196154    }
    197155
    198156  public:
    199     bool HasSortKey() const { return m_sort_key.isSet(); }
    200     const VideoMetadata::SortKey &GetSortKey() const { return m_sort_key; }
    201     void SetSortKey(const VideoMetadata::SortKey &sort_key)
    202     {
    203         m_sort_key = sort_key;
    204     }
    205 
    206157    const QString &GetPrefix() const { return m_prefix; }
    207158    void SetPrefix(const QString &prefix) { m_prefix = prefix; }
    208159
    209160    const QString &getTitle() const { return m_title; }
    210     void SetTitle(const QString& title)
     161    const QString &getSortTitle() const { return m_sortTitle; }
     162    void SetTitle(const QString& title, const QString& sortTitle)
    211163    {
    212         if (gCoreContext->HasGUI())
    213             m_sort_key.Clear();
    214164        m_title = title;
     165        m_sortTitle = sortTitle;
     166    }
     167    void SetTitle(const QString& title)
     168    {
     169        SortHelper *sh = new SortHelper;
     170        SetTitle(title, sh->doTitle(title));
    215171    }
    216172
    217173    const QString &getSubtitle() const { return m_subtitle; }
    218     void SetSubtitle(const QString &subtitle) { m_subtitle = subtitle; }
     174    const QString &getSortSubtitle() const { return m_sortSubtitle; }
     175    void SetSubtitle(const QString &subtitle, const QString &sortSubtitle) {
     176        m_subtitle = subtitle;
     177        m_sortSubtitle = sortSubtitle;
     178    }
     179    void SetSubtitle(const QString &subtitle) {
     180        SortHelper *sh = new SortHelper;
     181        SetSubtitle(subtitle, sh->doTitle(subtitle));
     182    }
    219183
    220184    const QString &GetTagline() const { return m_tagline; }
    221185    void SetTagline(const QString &tagline) { m_tagline = tagline; }
    class VideoMetadataImp  
    266230    void SetHost(const QString &host) { m_host = host; }
    267231
    268232    const QString &getFilename() const { return m_filename; }
    269     void SetFilename(const QString &filename) { m_filename = filename; }
     233    const QString &getSortFilename() const { return m_sortFilename; }
     234    void SetFilename(const QString &filename, const QString &sortFilename);
     235    void SetFilename(const QString &filename);
     236    bool sortBefore(const VideoMetadataImp *rhs) const;
    270237
    271238    const QString &GetHash() const { return m_hash; }
    272239    void SetHash(const QString &hash) { m_hash = hash; }
    class VideoMetadataImp  
    367334
    368335  private:
    369336    QString m_title;
     337    QString m_sortTitle;
    370338    QString m_subtitle;
     339    QString m_sortSubtitle;
    371340    QString m_tagline;
    372341    QString m_inetref;
    373342    int m_collectionref;
    class VideoMetadataImp  
    382351    country_list m_countries;
    383352    cast_list m_cast;
    384353    QString m_filename;
     354    QString m_sortFilename;
    385355    QString m_hash;
    386356    QString m_trailer;
    387357    QString m_coverfile;
    class VideoMetadataImp  
    408378    VideoContentType m_contenttype;
    409379
    410380    // not in DB
    411     VideoMetadata::SortKey m_sort_key;
    412381    QString m_prefix;
    413382};
    414383
    415384/////////////////////////////
    416385/////////
    417386/////////////////////////////
     387void VideoMetadataImp::SetFilename(const QString &filename, const QString &sortFilename) {
     388    m_filename = filename;
     389    m_sortFilename = sortFilename;
     390}
     391
     392void VideoMetadataImp::SetFilename(const QString &filename) {
     393    SortHelper *sh = new SortHelper;
     394    SetFilename(filename, sh->doPathname(filename));
     395}
     396
     397/** \fn VideoMetadataImp::sortBefore(const VideoMetadataImp *)
     398 *  \brief Returns true if the object should appear before the argument.
     399 */
     400bool VideoMetadataImp::sortBefore(const VideoMetadataImp *rhs) const
     401{
     402    int ret = naturalCompare(m_sortTitle, rhs->m_sortTitle);
     403    if (ret != 0)
     404        return (ret == -1);
     405    ret = naturalCompare(m_sortFilename, rhs->m_sortFilename);
     406    if (ret != 0)
     407        return (ret == -1);
     408    return (m_id < rhs->m_id);
     409}
     410
    418411bool VideoMetadataImp::removeDir(const QString &dirName)
    419412{
    420413    QDir d(dirName);
    bool VideoMetadataImp::DeleteFile()  
    477470
    478471void VideoMetadataImp::Reset()
    479472{
    480     VideoMetadataImp tmp(m_filename, VideoMetadata::VideoFileHash(m_filename, m_host), VIDEO_TRAILER_DEFAULT,
     473    VideoMetadataImp tmp(m_filename, QString(),
     474                    VideoMetadata::VideoFileHash(m_filename, m_host), VIDEO_TRAILER_DEFAULT,
    481475                    VIDEO_COVERFILE_DEFAULT, VIDEO_SCREENSHOT_DEFAULT, VIDEO_BANNER_DEFAULT,
    482                     VIDEO_FANART_DEFAULT, VideoMetadata::FilenameToMeta(m_filename, 1), QString(),
    483                     VideoMetadata::FilenameToMeta(m_filename, 4), VIDEO_YEAR_DEFAULT,
     476                    VIDEO_FANART_DEFAULT, QString(), QString(), QString(), QString(),
     477                    QString(), VIDEO_YEAR_DEFAULT,
    484478                    QDate(), VIDEO_INETREF_DEFAULT, -1, QString(), VIDEO_DIRECTOR_DEFAULT,
    485479                    QString(), VIDEO_PLOT_DEFAULT, 0.0,
    486480                    VIDEO_RATING_DEFAULT, 0, 0,
    487                     VideoMetadata::FilenameToMeta(m_filename, 2).toInt(),
    488                     VideoMetadata::FilenameToMeta(m_filename, 3).toInt(), QDate(), m_id,
     481                    0, 0, QDate(), m_id,
    489482                    ParentalLevel::plLowest, 0, -1, true, false, "", "",
    490483                    VideoMetadata::genre_list(), VideoMetadata::country_list(),
    491484                    VideoMetadata::cast_list(), m_host, false);
    void VideoMetadataImp::fillCast()  
    557550}
    558551
    559552/// Sets metadata from a DB row
     553///
     554/// Query in VideoMetadataListManager::loadAllFromDatabase
     555///
    560556void VideoMetadataImp::fromDBRow(MSqlQuery &query)
    561557{
    562558    m_title = query.value(0).toString();
    void VideoMetadataImp::fromDBRow(MSqlQuery &query)  
    600596
    601597    m_contenttype = ContentTypeFromString(query.value(34).toString());
    602598
     599    m_sortTitle = query.value(35).toString();
     600    m_sortSubtitle = query.value(36).toString();
     601    m_sortFilename = query.value(37).toString();
     602
    603603    VideoCategory::GetCategory().get(m_categoryID, m_category);
    604604
    605605    // Genres
    void VideoMetadataImp::fromDBRow(MSqlQuery &query)  
    614614
    615615void VideoMetadataImp::saveToDatabase()
    616616{
     617    SortHelper *sh = new SortHelper;
     618
    617619    if (m_title.isEmpty())
     620    {
    618621        m_title = VideoMetadata::FilenameToMeta(m_filename, 1);
     622        m_sortTitle = sh->doTitle(m_title);
     623    }
    619624    if (m_hash.isEmpty())
    620625        m_hash = VideoMetadata::VideoFileHash(m_filename, m_host);
    621626    if (m_subtitle.isEmpty())
     627    {
    622628        m_subtitle = VideoMetadata::FilenameToMeta(m_filename, 4);
     629        m_sortSubtitle = sh->doTitle(m_subtitle);
     630    }
    623631    if (m_director.isEmpty())
    624632        m_director = VIDEO_DIRECTOR_UNKNOWN;
    625633    if (m_plot.isEmpty())
    void VideoMetadataImp::saveToDatabase()  
    670678
    671679        m_watched = 0;
    672680
    673         query.prepare("INSERT INTO videometadata (title,subtitle,tagline,director,studio,plot,"
    674                       "rating,year,userrating,length,season,episode,filename,hash,"
     681        query.prepare("INSERT INTO videometadata (title,sorttitle,subtitle,sortsubtitle,"
     682                      "tagline,director,studio,plot,rating,year,userrating,length,"
     683                      "season,episode,filename,sortfilename,hash,"
    675684                      "showlevel,coverfile,inetref,homepage,browse,watched,trailer,"
    676                       "screenshot,banner,fanart,host,processed,contenttype) VALUES (:TITLE, :SUBTITLE, "
     685                      "screenshot,banner,fanart,host,processed,contenttype) "
     686                      "VALUES (:TITLE, :TITLESORT, :SUBTITLE, :SUBTITLESORT, "
    677687                      ":TAGLINE, :DIRECTOR, :STUDIO, :PLOT, :RATING, :YEAR, :USERRATING, "
    678                       ":LENGTH, :SEASON, :EPISODE, :FILENAME, :HASH, :SHOWLEVEL, "
     688                      ":LENGTH, :SEASON, :EPISODE, :FILENAME, :SORTFILENAME, :HASH, :SHOWLEVEL, "
    679689                      ":COVERFILE, :INETREF, :HOMEPAGE, :BROWSE, :WATCHED, "
    680690                      ":TRAILER, :SCREENSHOT, :BANNER, :FANART, :HOST, :PROCESSED, :CONTENTTYPE)");
    681691    }
    682692    else
    683693    {
    684         query.prepare("UPDATE videometadata SET title = :TITLE, subtitle = :SUBTITLE, "
     694        query.prepare("UPDATE videometadata SET title = :TITLE, sorttitle = :SORTTITLE, "
     695                      "subtitle = :SUBTITLE, sortsubtitle = :SORTSUBTITLE, "
    685696                      "tagline = :TAGLINE, director = :DIRECTOR, studio = :STUDIO, "
    686697                      "plot = :PLOT, rating= :RATING, year = :YEAR, "
    687698                      "releasedate = :RELEASEDATE, userrating = :USERRATING, "
    688699                      "length = :LENGTH, playcount = :PLAYCOUNT, season = :SEASON, "
    689                       "episode = :EPISODE, filename = :FILENAME, hash = :HASH, trailer = :TRAILER, "
     700                      "episode = :EPISODE, filename = :FILENAME, sortfilename = :SORTFILENAME, "
     701                      "hash = :HASH, trailer = :TRAILER, "
    690702                      "showlevel = :SHOWLEVEL, coverfile = :COVERFILE, "
    691703                      "screenshot = :SCREENSHOT, banner = :BANNER, fanart = :FANART, "
    692704                      "inetref = :INETREF, collectionref = :COLLECTION, homepage = :HOMEPAGE, "
    void VideoMetadataImp::saveToDatabase()  
    701713    }
    702714
    703715    query.bindValue(":TITLE", m_title.isNull() ? "" : m_title);
     716    query.bindValue(":SORTTITLE", m_sortTitle.isNull() ? "" : m_sortTitle);
    704717    query.bindValue(":SUBTITLE", m_subtitle.isNull() ? "" : m_subtitle);
     718    query.bindValue(":SORTSUBTITLE", m_sortSubtitle.isNull() ? "" : m_sortSubtitle);
    705719    query.bindValue(":TAGLINE", m_tagline);
    706720    query.bindValue(":DIRECTOR", m_director.isNull() ? "" : m_director);
    707721    query.bindValue(":STUDIO", m_studio);
    void VideoMetadataImp::saveToDatabase()  
    715729    query.bindValue(":SEASON", m_season);
    716730    query.bindValue(":EPISODE", m_episode);
    717731    query.bindValue(":FILENAME", m_filename);
     732    query.bindValue(":SORTFILENAME", m_sortFilename);
    718733    query.bindValue(":HASH", m_hash);
    719734    query.bindValue(":TRAILER", m_trailer.isNull() ? "" : m_trailer);
    720735    query.bindValue(":SHOWLEVEL", m_showlevel);
    void VideoMetadataImp::GetImageMap(InfoMap &imageMap) const  
    960975////////////////////////////////////////
    961976//// Metadata
    962977////////////////////////////////////////
    963 VideoMetadata::SortKey VideoMetadata::GenerateDefaultSortKey(const VideoMetadata &m,
    964                                                    bool ignore_case)
    965 {
    966     QString title(ignore_case ? m.GetTitle().toLower() : m.GetTitle());
    967     title = TrimTitle(title, ignore_case);
    968 
    969     return SortKey(SortData(title, m.GetFilename(),
    970                          QString().sprintf("%.7d", m.GetID())));
    971 }
    972 
    973978namespace
    974979{
    975980    QString eatBraces(const QString &title, const QString &left_brace,
    int VideoMetadata::UpdateHashedDBRecord(const QString &hash,  
    10221027                                   const QString &host)
    10231028{
    10241029    MSqlQuery query(MSqlQuery::InitCon());
     1030    SortHelper *sh = new SortHelper;
    10251031
    10261032    query.prepare("SELECT intid,filename FROM videometadata WHERE "
    10271033                  "hash = :HASH");
    int VideoMetadata::UpdateHashedDBRecord(const QString &hash,  
    10401046    QString oldfilename = query.value(1).toString();
    10411047
    10421048    query.prepare("UPDATE videometadata SET filename = :FILENAME, "
    1043                   "host = :HOST WHERE intid = :INTID");
     1049                  "sortfilename = :SORTFILENAME, host = :HOST "
     1050                  "WHERE intid = :INTID");
    10441051    query.bindValue(":FILENAME", file_name);
     1052    query.bindValue(":SORTFILENAME", sh->doPathname(file_name));
    10451053    query.bindValue(":HOST", host);
    10461054    query.bindValue(":INTID", intid);
    10471055
    QString VideoMetadata::FilenameToMeta(const QString &file_name, int position)  
    11721180    return QString();
    11731181}
    11741182
    1175 namespace
    1176 {
    1177     const QRegExp &getTitleTrim(bool ignore_case)
    1178     {
    1179         static QString pattern(VideoMetadata::tr("^(The |A |An )"));
    1180         static QRegExp prefixes_case(pattern, Qt::CaseSensitive);
    1181         static QRegExp prefixes_nocase(pattern, Qt::CaseInsensitive);
    1182         return ignore_case ? prefixes_nocase : prefixes_case;
    1183     }
    1184 }
    1185 
    1186 QString VideoMetadata::TrimTitle(const QString &title, bool ignore_case)
    1187 {
    1188     QString ret(title);
    1189     ret.remove(getTitleTrim(ignore_case));
    1190     return ret;
    1191 }
    1192 
    1193 VideoMetadata::VideoMetadata(const QString &filename, const QString &hash,
    1194              const QString &trailer, const QString &coverfile,
     1183VideoMetadata::VideoMetadata(const QString &filename, const QString &sortFilename,
     1184             const QString &hash, const QString &trailer, const QString &coverfile,
    11951185             const QString &screenshot, const QString &banner, const QString &fanart,
    1196              const QString &title, const QString &subtitle, const QString &tagline,
     1186             const QString &title, const QString &sortTitle,
     1187             const QString &subtitle, const QString &sortSubtitle, const QString &tagline,
    11971188             int year, const QDate &releasedate, const QString &inetref, int collectionref,
    11981189             const QString &homepage, const QString &director, const QString &studio,
    11991190             const QString &plot, float userrating, const QString &rating,
    VideoMetadata::VideoMetadata(const QString &filename, const QString &hash,  
    12071198             const QString &host, bool processed,
    12081199             VideoContentType contenttype)
    12091200{
    1210     m_imp = new VideoMetadataImp(filename, hash, trailer, coverfile, screenshot, banner,
    1211                             fanart, title, subtitle, tagline, year, releasedate, inetref,
     1201    m_imp = new VideoMetadataImp(filename, sortFilename, hash, trailer, coverfile,
     1202                            screenshot, banner, fanart, title, sortTitle, subtitle,
     1203                            sortSubtitle, tagline, year, releasedate, inetref,
    12121204                            collectionref, homepage, director, studio, plot, userrating, rating,
    12131205                            length, playcount, season, episode, insertdate, id, showlevel, categoryID,
    12141206                            childID, browse, watched, playcommand, category, genres, countries,
    void VideoMetadata::toMap(InfoMap &metadataMap)  
    12481240    GetImageMap(metadataMap);
    12491241
    12501242    metadataMap["filename"] = GetFilename();
     1243    metadataMap["sortfilename"] = GetSortFilename();
    12511244    metadataMap["title"] = GetTitle();
     1245    metadataMap["sorttitle"] = GetSortTitle();
    12521246    metadataMap["subtitle"] = GetSubtitle();
     1247    metadataMap["sortsubtitle"] = GetSortSubtitle();
    12531248    metadataMap["tagline"] = GetTagline();
    12541249    metadataMap["director"] = GetDirector();
    12551250    metadataMap["studio"] = GetStudio();
    void ClearMap(InfoMap &metadataMap)  
    13201315    metadataMap["bannerfile"] = "";
    13211316    metadataMap["fanartfile"] = "";
    13221317    metadataMap["filename"] = "";
     1318    metadataMap["sortfilename"] = "";
    13231319    metadataMap["title"] = "";
     1320    metadataMap["sorttitle"] = "";
    13241321    metadataMap["subtitle"] = "";
     1322    metadataMap["sortsubtitle"] = "";
    13251323    metadataMap["tagline"] = "";
    13261324    metadataMap["director"] = "";
    13271325    metadataMap["studio"] = "";
    void ClearMap(InfoMap &metadataMap)  
    13531351    metadataMap["processed"] = "";
    13541352}
    13551353
    1356 bool VideoMetadata::HasSortKey() const
    1357 {
    1358     return m_imp->HasSortKey();
    1359 }
    1360 
    1361 const VideoMetadata::SortKey &VideoMetadata::GetSortKey() const
    1362 {
    1363     return m_imp->GetSortKey();
    1364 }
    1365 
    1366 void VideoMetadata::SetSortKey(const VideoMetadata::SortKey &sort_key)
    1367 {
    1368     m_imp->SetSortKey(sort_key);
    1369 }
    1370 
    13711354const QString &VideoMetadata::GetPrefix() const
    13721355{
    13731356    return m_imp->GetPrefix();
    const QString &VideoMetadata::GetTitle() const  
    13831366    return m_imp->getTitle();
    13841367}
    13851368
     1369const QString &VideoMetadata::GetSortTitle() const
     1370{
     1371    return m_imp->getSortTitle();
     1372}
     1373
     1374void VideoMetadata::SetTitle(const QString &title, const QString &sortTitle)
     1375{
     1376    m_imp->SetTitle(title, sortTitle);
     1377}
     1378
    13861379void VideoMetadata::SetTitle(const QString &title)
    13871380{
    13881381    m_imp->SetTitle(title);
    const QString &VideoMetadata::GetSubtitle() const  
    13931386    return m_imp->getSubtitle();
    13941387}
    13951388
     1389const QString &VideoMetadata::GetSortSubtitle() const
     1390{
     1391    return m_imp->getSortSubtitle();
     1392}
     1393
     1394void VideoMetadata::SetSubtitle(const QString &subtitle, const QString &sortSubtitle)
     1395{
     1396    m_imp->SetSubtitle(subtitle, sortSubtitle);
     1397}
     1398
    13961399void VideoMetadata::SetSubtitle(const QString &subtitle)
    13971400{
    13981401    m_imp->SetSubtitle(subtitle);
    const QString &VideoMetadata::GetFilename() const  
    16431646    return m_imp->getFilename();
    16441647}
    16451648
     1649const QString &VideoMetadata::GetSortFilename() const
     1650{
     1651    return m_imp->getSortFilename();
     1652}
     1653
    16461654const QString &VideoMetadata::GetHash() const
    16471655{
    16481656    return m_imp->GetHash();
    void VideoMetadata::SetHost(const QString &host)  
    16631671        m_imp->SetHost(host);
    16641672}
    16651673
     1674void VideoMetadata::SetFilename(const QString &filename, const QString &sortFilename)
     1675{
     1676    m_imp->SetFilename(filename, sortFilename);
     1677}
     1678
    16661679void VideoMetadata::SetFilename(const QString &filename)
    16671680{
    16681681    m_imp->SetFilename(filename);
    bool VideoMetadata::IsHostSet() const  
    18311844    return m_imp->IsHostSet();
    18321845}
    18331846
     1847bool VideoMetadata::sortBefore(const VideoMetadata &rhs) const
     1848{
     1849    return m_imp->sortBefore(rhs.m_imp);
     1850}
     1851
    18341852bool operator==(const VideoMetadata& a, const VideoMetadata& b)
    18351853{
    18361854    if (a.GetFilename() == b.GetFilename())
    bool operator!=(const VideoMetadata& a, const VideoMetadata& b)  
    18441862        return true;
    18451863    return false;
    18461864}
    1847 
    1848 bool operator<(const VideoMetadata::SortKey &lhs, const VideoMetadata::SortKey &rhs)
    1849 {
    1850     if (lhs.m_sd && rhs.m_sd)
    1851         return *lhs.m_sd < *rhs.m_sd;
    1852     else
    1853     {
    1854         LOG(VB_GENERAL, LOG_ERR,
    1855             "Error: Bug, Metadata item with empty sort key compared");
    1856         return lhs.m_sd < rhs.m_sd;
    1857     }
    1858 }
  • mythtv/libs/libmythmetadata/videometadata.h

    diff --git a/mythtv/libs/libmythmetadata/videometadata.h b/mythtv/libs/libmythmetadata/videometadata.h
    index a02587c..5fb8289 100644
    a b enum { VIDEO_YEAR_DEFAULT = 1895 };  
    1919
    2020const QString VIDEO_SUBTITLE_DEFAULT = "";
    2121
    22 struct SortData;
    23 
    2422typedef QHash<QString,QString> MetadataMap;
    2523
    2624class META_PUBLIC VideoMetadata
    class META_PUBLIC VideoMetadata  
    3634    typedef std::vector<cast_entry> cast_list;
    3735
    3836  public:
    39     class META_PUBLIC SortKey
    40     {
    41       public:
    42         SortKey();
    43         explicit SortKey(const SortData &data);
    44         SortKey(const SortKey &other);
    45         SortKey &operator=(const SortKey &rhs);
    46         ~SortKey();
    47 
    48         bool isSet() const;
    49         void Clear();
    50 
    51       public:
    52         SortData *m_sd;
    53     };
    54 
    55   public:
    56     static SortKey GenerateDefaultSortKey(const VideoMetadata &m, bool ignore_case);
    5737    static int UpdateHashedDBRecord(const QString &hash, const QString &file_name,
    5838                                    const QString &host);
    5939    static QString VideoFileHash(const QString &file_name, const QString &host);
    class META_PUBLIC VideoMetadata  
    6242
    6343  public:
    6444    VideoMetadata(const QString &filename = QString(),
     45             const QString &sortFilename = QString(),
    6546             const QString &hash = QString(),
    6647             const QString &trailer = QString(),
    6748             const QString &coverfile = QString(),
    class META_PUBLIC VideoMetadata  
    6950             const QString &banner = QString(),
    7051             const QString &fanart = QString(),
    7152             const QString &title = QString(),
     53             const QString &sortTitle = QString(),
    7254             const QString &subtitle = QString(),
     55             const QString &sortSubtitle = QString(),
    7356             const QString &tagline = QString(),
    7457             int year = VIDEO_YEAR_DEFAULT,
    7558             const QDate &releasedate = QDate(),
    class META_PUBLIC VideoMetadata  
    10487    explicit VideoMetadata(MSqlQuery &query);
    10588    VideoMetadata(const VideoMetadata &rhs);
    10689    VideoMetadata &operator=(const VideoMetadata &rhs);
     90    bool sortBefore(const VideoMetadata &rhs) const;
    10791
    10892    void toMap(InfoMap &metadataMap);
    10993    void GetStateMap(InfoMap &stateMap);
    11094    void GetImageMap(InfoMap &imageMap);
    11195
    112     // returns a string to use when sorting
    113     bool HasSortKey() const;
    114     const SortKey &GetSortKey() const;
    115     void SetSortKey(const SortKey &sort_key);
    116 
    11796    const QString &GetPrefix() const;
    11897    void SetPrefix(const QString &prefix);
    11998
    12099    const QString &GetTitle() const;
     100    const QString &GetSortTitle() const;
     101    void SetTitle(const QString& title, const QString& sortTitle);
    121102    void SetTitle(const QString& title);
    122103
    123104    const QString &GetSubtitle() const;
     105    const QString &GetSortSubtitle() const;
     106    void SetSubtitle(const QString &subtitle, const QString &sortSubtitle);
    124107    void SetSubtitle(const QString &subtitle);
    125108
    126109    const QString &GetTagline() const;
    class META_PUBLIC VideoMetadata  
    199182    void SetHost(const QString &host);
    200183
    201184    const QString &GetFilename() const;
     185    const QString &GetSortFilename() const;
     186    void SetFilename(const QString &filename, const QString &sortFilename);
    202187    void SetFilename(const QString &filename);
    203188
    204189    const QString &GetHash() const;
    META_PUBLIC void ClearMap(InfoMap &metadataMap);  
    258243META_PUBLIC bool operator==(const VideoMetadata &a, const VideoMetadata &b);
    259244META_PUBLIC bool operator!=(const VideoMetadata &a, const VideoMetadata &b);
    260245
    261 META_PUBLIC bool operator<(const VideoMetadata::SortKey &lhs, const VideoMetadata::SortKey &rhs);
    262 
    263246Q_DECLARE_METATYPE(VideoMetadata*)
    264247
    265248#endif
  • mythtv/libs/libmythmetadata/videometadatalistmanager.cpp

    diff --git a/mythtv/libs/libmythmetadata/videometadatalistmanager.cpp b/mythtv/libs/libmythmetadata/videometadatalistmanager.cpp
    index e83198a..854ddb1 100644
    a b  
    22
    33#include "mythdb.h"
    44#include "videometadatalistmanager.h"
     5#include "mythsorthelper.h"
    56
    67class VideoMetadataListManagerImp
    78{
    VideoMetadataListManager::loadOneFromDatabase(uint id)  
    120121    return VideoMetadataPtr(new VideoMetadata());
    121122}
    122123
     124/// Load videometadata database into memory
     125///
     126/// Query consumed in VideoMetadataImp::fromDBRow
     127///
    123128void VideoMetadataListManager::loadAllFromDatabase(metadata_list &items,
    124129                                                   const QString &sql)
    125130{
    126131    MSqlQuery query(MSqlQuery::InitCon());
    127132    query.setForwardOnly(true);
    128133    QString BaseMetadataQuery(
    129         "SELECT title, director, studio, plot, rating, year, releasedate,"
    130         "userrating, length, playcount, filename, hash, showlevel, "
    131         "coverfile, inetref, collectionref, homepage, childid, browse, watched, "
    132         "playcommand, category, intid, trailer, screenshot, banner, fanart, "
    133         "subtitle, tagline, season, episode, host, insertdate, processed, "
    134         "contenttype FROM videometadata ");
     134        "SELECT title, director, studio, plot, rating, year, releasedate," // 0-6
     135        "userrating, length, playcount, filename, hash, showlevel, "       // 7-12
     136        "coverfile, inetref, collectionref, homepage, childid, browse, watched, " // 13-19
     137        "playcommand, category, intid, trailer, screenshot, banner, fanart, " // 20-26
     138        "subtitle, tagline, season, episode, host, insertdate, processed, " // 27-33
     139        "contenttype, sorttitle, sortsubtitle, sortfilename " // 34-37
     140        "FROM videometadata ");
    135141
    136142    if (!sql.isEmpty())
    137143        BaseMetadataQuery.append(sql);
    meta_dir_node::meta_dir_node(const QString &path, const QString &name,  
    249255  : meta_node(parent, is_path_root), m_path(path), m_name(name),
    250256    m_host(host), m_prefix(prefix), m_data(data)
    251257{
     258    SortHelper *sh = new SortHelper;
     259    m_sortPath = sh->doPathname(m_path);
     260
    252261    if (!name.length())
    253262        m_name = path;
    254263}
    const QString &meta_dir_node::getPath() const  
    288297    return m_path;
    289298}
    290299
    291 void meta_dir_node::setPath(const QString &path)
     300const QString &meta_dir_node::getSortPath() const
     301{
     302    return m_sortPath;
     303}
     304
     305void meta_dir_node::setPath(const QString &path, const QString &sortPath)
    292306{
    293307    m_path = path;
     308    m_sortPath = sortPath;
     309}
     310
     311void meta_dir_node::setPath(const QString &path)
     312{
     313    SortHelper *sh = new SortHelper;
     314    setPath(path, sh->doPathname(path));
    294315}
    295316
    296317void meta_dir_node::SetData(const QVariant &data)
  • mythtv/libs/libmythmetadata/videometadatalistmanager.h

    diff --git a/mythtv/libs/libmythmetadata/videometadatalistmanager.h b/mythtv/libs/libmythmetadata/videometadatalistmanager.h
    index 002f88c..cfc4e1c 100644
    a b class META_PUBLIC meta_dir_node : public meta_node  
    102102    void SetPrefix(const QString &prefix);
    103103    const QString &GetPrefix() const;
    104104    const QString &getPath() const;
     105    const QString &getSortPath() const;
     106    void setPath(const QString &path, const QString &sortPath);
    105107    void setPath(const QString &path);
    106108    void SetData(const QVariant &data);
    107109    const QVariant &GetData() const;
    class META_PUBLIC meta_dir_node : public meta_node  
    146148
    147149  private:
    148150    QString m_path;
     151    QString m_sortPath;
    149152    QString m_name;
    150153    QString m_host;
    151154    QString m_prefix;
  • mythtv/libs/libmythmetadata/videoscan.cpp

    diff --git a/mythtv/libs/libmythmetadata/videoscan.cpp b/mythtv/libs/libmythmetadata/videoscan.cpp
    index e40c792..72cf2a0 100644
    a b bool VideoScannerThread::updateDB(const FileCheckList &add, const PurgeList &rem  
    340340            if (id == -1)
    341341            {
    342342                VideoMetadata newFile(
    343                     p->first, hash,
     343                    p->first, QString(), hash,
    344344                    VIDEO_TRAILER_DEFAULT,
    345345                    VIDEO_COVERFILE_DEFAULT,
    346346                    VIDEO_SCREENSHOT_DEFAULT,
    347347                    VIDEO_BANNER_DEFAULT,
    348348                    VIDEO_FANART_DEFAULT,
    349                     VideoMetadata::FilenameToMeta(p->first, 1),
    350                     VideoMetadata::FilenameToMeta(p->first, 4),
     349                    QString(), QString(), QString(), QString(),
    351350                    QString(),
    352351                    VIDEO_YEAR_DEFAULT,
    353352                    QDate::fromString("0000-00-00","YYYY-MM-DD"),
    354353                    VIDEO_INETREF_DEFAULT, 0, QString(),
    355354                    VIDEO_DIRECTOR_DEFAULT, QString(), VIDEO_PLOT_DEFAULT,
    356355                    0.0, VIDEO_RATING_DEFAULT, 0, 0,
    357                     VideoMetadata::FilenameToMeta(p->first, 2).toInt(),
    358                     VideoMetadata::FilenameToMeta(p->first, 3).toInt(),
     356                    0, 0,
    359357                    MythDate::current().date(),
    360358                    0, ParentalLevel::plLowest);
    361359
  • mythtv/libs/libmythtv/datadirect.cpp

    diff --git a/mythtv/libs/libmythtv/datadirect.cpp b/mythtv/libs/libmythtv/datadirect.cpp
    index 7c62597..fc44eef 100644
    a b  
    2626#include "mythdownloadmanager.h"
    2727#include "mythtvexp.h"
    2828#include "mythdate.h"
     29#include "mythsorthelper.h"
    2930
    3031#define LOC QString("DataDirect: ")
    3132
    bool DDStructureParser::endElement(const QString &pnamespaceuri,  
    212213    (void)pnamespaceuri;
    213214    (void)plocalname;
    214215
     216    SortHelper *sh = new SortHelper;
    215217    MSqlQuery query(MSqlQuery::DDCon());
    216218
    217219    if (pqname == "station")
    bool DDStructureParser::endElement(const QString &pnamespaceuri,  
    336338
    337339        query.prepare(
    338340            "INSERT INTO dd_program "
    339             "     ( programid,    title,       subtitle,       "
     341            "     ( programid,    title,       sorttitle,      "
     342            "       subtitle,     sortsubtitle,                "
    340343            "       description,  showtype,    category_type,  "
    341344            "       mpaarating,   starrating,  stars,          "
    342345            "       runtime,      year,        seriesid,       "
    343346            "       colorcode,    syndicatedepisodenumber, originalairdate) "
    344347            "VALUES "
    345             "     (:PROGRAMID,   :TITLE,      :SUBTITLE,       "
     348            "     (:PROGRAMID,   :TITLE,      :SORTTITLE,      "
     349            "      :SUBTITLE,    :SORTSUBTITLE,                "
    346350            "      :DESCRIPTION, :SHOWTYPE,   :CATTYPE,        "
    347351            "      :MPAARATING,  :STARRATING, :STARS,          "
    348352            "      :RUNTIME,     :YEAR,       :SERIESID,       "
    bool DDStructureParser::endElement(const QString &pnamespaceuri,  
    350354
    351355        query.bindValue(":PROGRAMID",   curr_program.programid);
    352356        query.bindValue(":TITLE",       curr_program.title);
     357        query.bindValue(":SORTTITLE",   sh->doTitle(curr_program.title));
    353358        query.bindValue(":SUBTITLE",    curr_program.subtitle);
     359        query.bindValue(":SORTSUBTITLE",sh->doTitle(curr_program.subtitle));
    354360        query.bindValue(":DESCRIPTION", curr_program.description);
    355361        query.bindValue(":SHOWTYPE",    curr_program.showtype);
    356362        query.bindValue(":CATTYPE",     cat_type);
    void DataDirectProcessor::UpdateProgramViewTable(uint sourceid)  
    635641    QString qstr =
    636642        "INSERT INTO dd_v_program "
    637643        "     ( chanid,                  starttime,       endtime,         "
    638         "       title,                   subtitle,        description,     "
     644        "       title,                   sorttitle,                        "
     645        "       subtitle,                sortsubtitle,    description,     "
    639646        "       airdate,                 stars,           previouslyshown, "
    640647        "       stereo,                  dolby,           subtitled,       "
    641648        "       hdtv,                    closecaptioned,  partnumber,      "
    void DataDirectProcessor::UpdateProgramViewTable(uint sourceid)  
    644651        "       syndicatedepisodenumber, tvrating,        mpaarating,      "
    645652        "       programid )      "
    646653        "SELECT chanid,                  scheduletime,    endtime,         "
    647         "       title,                   subtitle,        description,     "
     654        "       title,                   sorttitle,                        "
     655        "       subtitle,                sortsubtitle,    description,     "
    648656        "       year,                    stars,           isrepeat,        "
    649657        "       stereo,                  dolby,           subtitled,       "
    650658        "       hdtv,                    closecaptioned,  partnumber,      "
    void DataDirectProcessor::DataDirectProgramUpdate(void)  
    840848#endif
    841849    query.prepare(
    842850        "INSERT IGNORE INTO program "
    843         "  ( chanid,        starttime,   endtime,         title,           "
    844         "    subtitle,      description, showtype,        category,        "
     851        "  ( chanid,        starttime,   endtime,                          "
     852        "    title,         sorttitle,   subtitle,        sortsubtitle,    "
     853        "                   description, showtype,        category,        "
    845854        "    category_type, airdate,     stars,           previouslyshown, "
    846855        "    stereo,        subtitled,   subtitletypes,   videoprop,       "
    847856        "    audioprop,     hdtv,        closecaptioned,  partnumber,      "
    void DataDirectProcessor::DataDirectProgramUpdate(void)  
    852861        "    dd_v_program.chanid,                                          "
    853862        "    DATE_ADD(starttime, INTERVAL channel.tmoffset MINUTE),        "
    854863        "    DATE_ADD(endtime, INTERVAL channel.tmoffset MINUTE),          "
    855         "                                                 title,           "
    856         "    subtitle,      description, showtype,        dd_genre.class,  "
     864        "    title,         sorttitle,   subtitle,        sortsubtitle,    "
     865        "                   description, showtype,        dd_genre.class,  "
    857866        "    category_type, airdate,     stars,           previouslyshown, "
    858867        "    stereo,        subtitled,                                     "
    859868        "    (subtitled << 1 ) | closecaptioned, hdtv,                     "
    void DataDirectProcessor::CreateTempTables()  
    13061315
    13071316    dd_tables["dd_program"] =
    13081317        "( programid char(40) NOT NULL,  seriesid char(12),     "
    1309         "  title varchar(120),           subtitle varchar(150), "
     1318        "  title varchar(120),           sorttitle varchar(120), "
     1319        "  subtitle varchar(150),        sortsubtitle varchar(150), "
    13101320        "  description text,             mpaarating char(5),    "
    13111321        "  starrating char(5),           runtime time,          "
    13121322        "  year char(4),                 showtype char(30),     "
    void DataDirectProcessor::CreateTempTables()  
    13181328    dd_tables["dd_v_program"] =
    13191329        "( chanid int unsigned NOT NULL, starttime datetime NOT NULL, "
    13201330        "  endtime datetime,             title varchar(128),          "
    1321         "  subtitle varchar(128),        description text,            "
     1331        "  sorttitle varchar(128),       subtitle varchar(128),       "
     1332        "  sortsubtitle varchar(128),    description text,            "
    13221333        "  category varchar(64),         category_type varchar(64),   "
    13231334        "  airdate year,                 stars float unsigned,        "
    13241335        "  previouslyshown tinyint,      isrepeat bool,               "
  • mythtv/libs/libmythtv/dbcheck.cpp

    diff --git a/mythtv/libs/libmythtv/dbcheck.cpp b/mythtv/libs/libmythtv/dbcheck.cpp
    index a0892ce..b88c179 100644
    a b using namespace std;  
    1818#include "recordingprofile.h"
    1919#include "recordinginfo.h"
    2020#include "cardutil.h"
     21#include "mythsorthelper.h"
    2122
    2223// TODO convert all dates to UTC
    2324
    bool UpgradeTVDatabaseSchema(const bool upgradeAllowed,  
    542543    return false;
    543544}
    544545
     546
     547/** \fn populateSortColumn(const char *, const char *)
     548 *  \brief Called by doUpgradeTVDatabaseSchema() to populate a single
     549 *         sort column.
     550 *
     551 *   This function populates the information ins a single sort
     552 *   column. The sort column has the same name as the original column
     553 *   with the name "sort" appended. I.E. The sort data for the column
     554 *   "title" is put into column "sorttitle". This function attempts to
     555 *   be efficient by asking the database to only return distinct
     556 *   entries. The "ORDER" clause should eventually be dropped.
     557 *
     558 *  \param table The name of the table to update.
     559 *
     560 *  \param column The name of a column whose sort data should be
     561 *                populated.
     562 *
     563 *  \return true on success, false on failure
     564 */
     565static bool populateSortColumn(const char *table, const char *column, int num = 0, int total = 0)
     566{
     567    MSqlQuery select(MSqlQuery::InitCon());
     568    MSqlQuery update(MSqlQuery::InitCon());
     569    SortHelper *sh = new SortHelper;
     570
     571    QString thequery = QString("SELECT DISTINCT(%1) AS %1 FROM %2 ORDER BY %1")
     572                               .arg(column).arg(table);
     573    QString theupdate = QString("UPDATE %1 SET sort%2=:SORT WHERE %2=:ORIG")
     574                                .arg(table).arg(column);
     575
     576    if (!select.exec(thequery))
     577    {
     578        MythDB::DBError(QString("Unable to retrieve %1 %2 information.")
     579                        .arg(table).arg(column), select);
     580        return false;
     581    }
     582    while (select.next())
     583    {
     584        update.prepare(theupdate);
     585        QString string = select.value(0).toString();
     586        QString sortString = (strcmp(column,"filename") == 0)
     587            ? sh->doPathname(string) : sh->doTitle(string);
     588        update.bindValue(":ORIG", string);
     589        update.bindValue(":SORT", sortString);
     590        if (!update.exec())
     591        {
     592            MythDB::DBError(QString("Unable to update %1 %2 information.")
     593                            .arg(table).arg(column), update);
     594            return false;
     595        }
     596    }
     597    if (num > 0)
     598        LOG(VB_GENERAL, LOG_INFO, QString("Populated %1 table [%2/%3].")
     599            .arg(table).arg(num).arg(total));
     600    return true;
     601}
     602
     603static bool populateSortColumns(const char *table, const char *column1, const char *column2, int num = 0, int total = 0)
     604{
     605    bool result = populateSortColumn(table, column1);
     606    result &= populateSortColumn(table, column2);
     607    if (num > 0)
     608        LOG(VB_GENERAL, LOG_INFO, QString("Populated %1 table [%2/%3].")
     609            .arg(table).arg(num).arg(total));
     610    return result;
     611}
     612
    545613/** \fn doUpgradeTVDatabaseSchema(void)
    546614 *  \brief This is called by UpgradeTVDatabaseSchema() to actually upgrade
    547615 *         the schema to what MythTV expects.
    NULL  
    33313399            return false;
    33323400    }
    33333401
     3402    if (dbver == "1346")
     3403    {
     3404        const char *updates[] = {
     3405            "ALTER TABLE internetcontentarticles "
     3406            "    ADD COLUMN sorttitle varchar(255) NOT NULL AFTER title,"
     3407            "    ADD COLUMN sortsubtitle varchar(255) NOT NULL AFTER subtitle",
     3408            "ALTER TABLE oldrecorded "
     3409            "    ADD COLUMN sorttitle varchar(128) NOT NULL AFTER title,"
     3410            "    ADD COLUMN sortsubtitle varchar(128) NOT NULL AFTER subtitle,"
     3411            "    ADD KEY sorttitle (sorttitle),"
     3412            "    ADD KEY sortsubtitle (sortsubtitle)",
     3413            "ALTER TABLE program "
     3414            "    ADD COLUMN sorttitle varchar(128) NOT NULL AFTER title,"
     3415            "    ADD COLUMN sortsubtitle varchar(128) NOT NULL AFTER subtitle,"
     3416            "    ADD KEY sorttitle (sorttitle),"
     3417            "    ADD KEY sortsubtitle (sortsubtitle)",
     3418            "ALTER TABLE record "
     3419            "    ADD COLUMN sorttitle varchar(128) NOT NULL AFTER title,"
     3420            "    ADD COLUMN sortsubtitle varchar(128) NOT NULL AFTER subtitle,"
     3421            "    ADD KEY sorttitle (sorttitle)",
     3422            "ALTER TABLE recorded "
     3423            "    ADD COLUMN sorttitle varchar(128) NOT NULL AFTER title,"
     3424            "    ADD COLUMN sortsubtitle varchar(128) NOT NULL AFTER subtitle,"
     3425            "    ADD KEY sorttitle (sorttitle)",
     3426            "ALTER TABLE recordedprogram "
     3427            "    ADD COLUMN sorttitle varchar(128) NOT NULL AFTER title,"
     3428            "    ADD COLUMN sortsubtitle varchar(128) NOT NULL AFTER subtitle,"
     3429            "    ADD KEY sorttitle (sorttitle)",
     3430            "ALTER TABLE videometadata "
     3431            "    ADD COLUMN sorttitle varchar(128) NOT NULL AFTER title,"
     3432            "    ADD COLUMN sortsubtitle varchar(128) NOT NULL AFTER subtitle,"
     3433            "    ADD COLUMN sortfilename text NOT NULL AFTER filename,"
     3434            "    ADD KEY sorttitle (sorttitle)",
     3435            NULL
     3436        };
     3437
     3438        if (!performUpdateSeries(updates))
     3439            return false;
     3440        LOG(VB_GENERAL, LOG_INFO, "Populating sort columns. This may take some time.");
     3441        if (!populateSortColumns("internetcontentarticles", "title", "subtitle", 1, 8)
     3442            or !populateSortColumns("oldrecorded", "title", "subtitle", 2, 8)
     3443            or !populateSortColumns("program", "title", "subtitle", 3, 8)
     3444            or !populateSortColumns("record", "title", "subtitle", 4, 8)
     3445            or !populateSortColumns("recorded", "title", "subtitle", 5, 8)
     3446            or !populateSortColumns("recordedprogram", "title", "subtitle", 6, 8)
     3447            or !populateSortColumn("videometadata", "filename", 7, 8)
     3448            or !populateSortColumns("videometadata", "title", "subtitle", 8, 8))
     3449            return false;
     3450        if (!UpdateDBVersionNumber("1347", dbver))
     3451            return false;
     3452    }
     3453
    33343454    /*
    33353455     * TODO the following settings are no more, clean them up with the next schema change
    33363456     * to avoid confusion by stale settings in the database
    bool InitializeMythSchema(void)  
    37363856"  path text NOT NULL,"
    37373857"  paththumb text NOT NULL,"
    37383858"  title varchar(255) NOT NULL,"
     3859"  sorttitle varchar(255) NOT NULL,"
    37393860"  subtitle varchar(255) NOT NULL,"
     3861"  sortsubtitle varchar(255) NOT NULL,"
    37403862"  season smallint(5) NOT NULL DEFAULT '0',"
    37413863"  episode smallint(5) NOT NULL DEFAULT '0',"
    37423864"  description text NOT NULL,"
    bool InitializeMythSchema(void)  
    38904012"  starttime datetime NOT NULL DEFAULT '0000-00-00 00:00:00',"
    38914013"  endtime datetime NOT NULL DEFAULT '0000-00-00 00:00:00',"
    38924014"  title varchar(128) NOT NULL DEFAULT '',"
     4015"  sorttitle varchar(128) NOT NULL DEFAULT '',"
    38934016"  subtitle varchar(128) NOT NULL DEFAULT '',"
     4017"  sortsubtitle varchar(128) NOT NULL DEFAULT '',"
    38944018"  description varchar(16000) NOT NULL DEFAULT '',"
    38954019"  season smallint(5) NOT NULL,"
    38964020"  episode smallint(5) NOT NULL,"
    bool InitializeMythSchema(void)  
    39104034"  PRIMARY KEY (station,starttime,title),"
    39114035"  KEY endtime (endtime),"
    39124036"  KEY title (title),"
     4037"  KEY sorttitle (sorttitle),"
    39134038"  KEY seriesid (seriesid),"
    39144039"  KEY programid (programid),"
    39154040"  KEY recordid (recordid),"
    bool InitializeMythSchema(void)  
    39184043"  KEY future (future),"
    39194044"  KEY chanid (chanid,starttime),"
    39204045"  KEY subtitle (subtitle),"
     4046"  KEY sortsubtitle (sortsubtitle),"
    39214047"  KEY description (description(255))"
    39224048") ENGINE=MyISAM DEFAULT CHARSET=utf8;",
    39234049"CREATE TABLE people ("
    bool InitializeMythSchema(void)  
    39624088"  starttime datetime NOT NULL DEFAULT '0000-00-00 00:00:00',"
    39634089"  endtime datetime NOT NULL DEFAULT '0000-00-00 00:00:00',"
    39644090"  title varchar(128) NOT NULL DEFAULT '',"
     4091"  sorttitle varchar(128) NOT NULL DEFAULT '',"
    39654092"  subtitle varchar(128) NOT NULL DEFAULT '',"
     4093"  sortsubtitle varchar(128) NOT NULL DEFAULT '',"
    39664094"  description varchar(16000) NOT NULL DEFAULT '',"
    39674095"  category varchar(64) NOT NULL DEFAULT '',"
    39684096"  category_type varchar(64) NOT NULL DEFAULT '',"
    bool InitializeMythSchema(void)  
    39934121"  PRIMARY KEY (chanid,starttime,manualid),"
    39944122"  KEY endtime (endtime),"
    39954123"  KEY title (title),"
     4124"  KEY sorttitle (sorttitle),"
    39964125"  KEY title_pronounce (title_pronounce),"
    39974126"  KEY seriesid (seriesid),"
    39984127"  KEY id_start_end (chanid,starttime,endtime),"
    bool InitializeMythSchema(void)  
    40014130"  KEY programid (programid,starttime),"
    40024131"  KEY starttime (starttime),"
    40034132"  KEY subtitle (subtitle),"
     4133"  KEY sortsubtitle (sortsubtitle),"
    40044134"  KEY description (description(255))"
    40054135") ENGINE=MyISAM DEFAULT CHARSET=utf8;",
    40064136"CREATE TABLE programgenres ("
    bool InitializeMythSchema(void)  
    40334163"  endtime time NOT NULL DEFAULT '00:00:00',"
    40344164"  enddate date NOT NULL DEFAULT '0000-00-00',"
    40354165"  title varchar(128) NOT NULL DEFAULT '',"
     4166"  sorttitle varchar(128) NOT NULL DEFAULT '',"
    40364167"  subtitle varchar(128) NOT NULL DEFAULT '',"
     4168"  sortsubtitle varchar(128) NOT NULL DEFAULT '',"
    40374169"  description varchar(16000) NOT NULL DEFAULT '',"
    40384170"  season smallint(5) NOT NULL,"
    40394171"  episode smallint(5) NOT NULL,"
    bool InitializeMythSchema(void)  
    40774209"  PRIMARY KEY (recordid),"
    40784210"  KEY chanid (chanid,starttime),"
    40794211"  KEY title (title),"
     4212"  KEY sorttitle (sorttitle),"
    40804213"  KEY seriesid (seriesid),"
    40814214"  KEY programid (programid),"
    40824215"  KEY maxepisodes (maxepisodes),"
    bool InitializeMythSchema(void)  
    40884221"  starttime datetime NOT NULL DEFAULT '0000-00-00 00:00:00',"
    40894222"  endtime datetime NOT NULL DEFAULT '0000-00-00 00:00:00',"
    40904223"  title varchar(128) NOT NULL DEFAULT '',"
     4224"  sorttitle varchar(128) NOT NULL DEFAULT '',"
    40914225"  subtitle varchar(128) NOT NULL DEFAULT '',"
     4226"  sortsubtitle varchar(128) NOT NULL DEFAULT '',"
    40924227"  description varchar(16000) NOT NULL DEFAULT '',"
    40934228"  season smallint(5) NOT NULL,"
    40944229"  episode smallint(5) NOT NULL,"
    bool InitializeMythSchema(void)  
    41304265"  KEY seriesid (seriesid),"
    41314266"  KEY programid (programid),"
    41324267"  KEY title (title),"
     4268"  KEY sorttitle (sorttitle),"
    41334269"  KEY recordid (recordid),"
    41344270"  KEY deletepending (deletepending,lastmodified),"
    41354271"  KEY recgroup (recgroup,endtime)"
    bool InitializeMythSchema(void)  
    41854321"  starttime datetime NOT NULL DEFAULT '0000-00-00 00:00:00',"
    41864322"  endtime datetime NOT NULL DEFAULT '0000-00-00 00:00:00',"
    41874323"  title varchar(128) NOT NULL DEFAULT '',"
     4324"  sorttitle varchar(128) NOT NULL DEFAULT '',"
    41884325"  subtitle varchar(128) NOT NULL DEFAULT '',"
     4326"  sortsubtitle varchar(128) NOT NULL DEFAULT '',"
    41894327"  description varchar(16000) NOT NULL DEFAULT '',"
    41904328"  category varchar(64) NOT NULL DEFAULT '',"
    41914329"  category_type varchar(64) NOT NULL DEFAULT '',"
    bool InitializeMythSchema(void)  
    42164354"  PRIMARY KEY (chanid,starttime,manualid),"
    42174355"  KEY endtime (endtime),"
    42184356"  KEY title (title),"
     4357"  KEY sorttitle (sorttitle),"
    42194358"  KEY title_pronounce (title_pronounce),"
    42204359"  KEY seriesid (seriesid),"
    42214360"  KEY programid (programid),"
    bool InitializeMythSchema(void)  
    43284467"  itemproperties varchar(255) NOT NULL DEFAULT '',"
    43294468"  filepath varchar(512) NOT NULL DEFAULT '',"
    43304469"  title varchar(255) NOT NULL DEFAULT '',"
     4470"  sorttitle varchar(255) NOT NULL DEFAULT '',"
    43314471"  filename varchar(512) NOT NULL DEFAULT '',"
    43324472"  coverart varchar(512) NOT NULL DEFAULT '',"
    43334473"  PRIMARY KEY (intid),"
    bool InitializeMythSchema(void)  
    43794519"CREATE TABLE videometadata ("
    43804520"  intid int(10) unsigned NOT NULL AUTO_INCREMENT,"
    43814521"  title varchar(128) NOT NULL,"
     4522"  sorttitle varchar(128) NOT NULL,"
    43824523"  subtitle text NOT NULL,"
     4524"  sortsubtitle text NOT NULL,"
    43834525"  tagline varchar(255) DEFAULT NULL,"
    43844526"  director varchar(128) NOT NULL,"
    43854527"  studio varchar(128) DEFAULT NULL,"
    bool InitializeMythSchema(void)  
    43974539"  episode smallint(5) unsigned NOT NULL DEFAULT '0',"
    43984540"  showlevel int(10) unsigned NOT NULL,"
    43994541"  filename text NOT NULL,"
     4542"  sortFilename text NOT NULL,"
    44004543"  `hash` varchar(128) NOT NULL,"
    44014544"  coverfile text NOT NULL,"
    44024545"  childid int(11) NOT NULL DEFAULT '-1',"
    bool InitializeMythSchema(void)  
    44144557"  contenttype set('MOVIE','TELEVISION','ADULT','MUSICVIDEO','HOMEVIDEO') NOT NULL DEFAULT '',"
    44154558"  PRIMARY KEY (intid),"
    44164559"  KEY director (director),"
    4417 "  KEY title (title)"
     4560"  KEY title (title),"
     4561"  KEY titlesort (titlesort)"
    44184562") ENGINE=MyISAM DEFAULT CHARSET=utf8;",
    44194563"CREATE TABLE videometadatacast ("
    44204564"  idvideo int(10) unsigned NOT NULL,"
  • mythtv/libs/libmythtv/eithelper.cpp

    diff --git a/mythtv/libs/libmythtv/eithelper.cpp b/mythtv/libs/libmythtv/eithelper.cpp
    index 5412770..0c57065 100644
    a b void EITHelper::AddEIT(const DVBEventInformationTable *eit)  
    684684        QDateTime endtime   = starttime.addSecs(eit->DurationInSeconds(i));
    685685
    686686        DBEventEIT *event = new DBEventEIT(
    687             chanid,
    688             title,     subtitle,      description,
     687            chanid,    title,         QString(),
     688            subtitle,  QString(),  description,
    689689            category,  category_type,
    690690            starttime, endtime,       fix,
    691691            subtitle_type,
    void EITHelper::AddEIT(const PremiereContentInformationTable *cit)  
    795795            QDateTime endtime   = starttime.addSecs(cit->DurationInSeconds());
    796796
    797797            DBEventEIT *event = new DBEventEIT(
    798                 chanid,
    799                 title,     subtitle,      description,
     798                chanid,    title,         QString(),
     799                subtitle,  QString(),  description,
    800800                category,  category_type,
    801801                starttime, endtime,       fix,
    802802                subtitle_type,
  • mythtv/libs/libmythtv/programdata.cpp

    diff --git a/mythtv/libs/libmythtv/programdata.cpp b/mythtv/libs/libmythtv/programdata.cpp
    index f99b0d8..3472b83 100644
    a b using namespace std;  
    1515#include "mythdb.h"
    1616#include "mythlogging.h"
    1717#include "dvbdescriptors.h"
     18#include "mythsorthelper.h"
    1819
    1920#define LOC      QString("ProgramData: ")
    2021
    uint DBEvent::GetOverlappingPrograms(  
    363364        "       previouslyshown,listingsource, "
    364365        "       stars+0, "
    365366        "       season,         episode,       totalepisodes, "
    366         "       inetref "
     367        "       inetref,        sorttitle,     sortsubtitle "
    367368        "FROM program "
    368369        "WHERE chanid   = :CHANID AND "
    369370        "      manualid = 0       AND "
    uint DBEvent::GetOverlappingPrograms(  
    391392
    392393        DBEvent prog(
    393394            query.value(0).toString(),
     395            query.value(24).toString(),
    394396            query.value(1).toString(),
     397            query.value(25).toString(),
    395398            query.value(2).toString(),
    396399            query.value(3).toString(),
    397400            category_type,
    uint DBEvent::UpdateDB(  
    617620    MSqlQuery &query, uint chanid, const DBEvent &match)  const
    618621{
    619622    QString  ltitle     = title;
     623    QString  lsortTitle = sortTitle;
    620624    QString  lsubtitle  = subtitle;
     625    QString  lsortSubtitle  = sortSubtitle;
    621626    QString  ldesc      = description;
    622627    QString  lcategory  = category;
    623628    uint16_t lairdate   = airdate;
    uint DBEvent::UpdateDB(  
    627632    QDate loriginalairdate = originalairdate;
    628633
    629634    if (match.title.length() >= ltitle.length())
     635    {
    630636        ltitle = match.title;
     637        lsortTitle = match.sortTitle;
     638    }
    631639
    632640    if (match.subtitle.length() >= lsubtitle.length())
     641    {
    633642        lsubtitle = match.subtitle;
     643        lsortSubtitle = match.sortSubtitle;
     644    }
    634645
    635646    if (match.description.length() >= ldesc.length())
    636647        ldesc = match.description;
    uint DBEvent::UpdateDB(  
    694705
    695706    query.prepare(
    696707        "UPDATE program "
    697         "SET title          = :TITLE,     subtitle      = :SUBTITLE, "
     708        "SET title          = :TITLE,     sorttitle     = :SORTTITLE, "
     709        "    subtitle       = :SUBTITLE,  sortsubtitle  = :SORTSUBTITLE, "
    698710        "    description    = :DESC, "
    699711        "    category       = :CATEGORY,  category_type = :CATTYPE, "
    700712        "    starttime      = :STARTTIME, endtime       = :ENDTIME, "
    uint DBEvent::UpdateDB(  
    716728    query.bindValue(":CHANID",      chanid);
    717729    query.bindValue(":OLDSTART",    match.starttime);
    718730    query.bindValue(":TITLE",       denullify(ltitle));
     731    query.bindValue(":SORTTITLE",   denullify(lsortTitle));
    719732    query.bindValue(":SUBTITLE",    denullify(lsubtitle));
     733    query.bindValue(":SORTSUBTITLE", denullify(lsortSubtitle));
    720734    query.bindValue(":DESC",        denullify(ldesc));
    721735    query.bindValue(":CATEGORY",    denullify(lcategory));
    722736    query.bindValue(":CATTYPE",     lcattype);
    uint DBEvent::UpdateDB(  
    745759
    746760    if (!query.exec())
    747761    {
    748         MythDB::DBError("InsertDB", query);
     762        MythDB::DBError("UpdateDB", query);
    749763        return 0;
    750764    }
    751765
    bool DBEvent::MoveOutOfTheWayDB(  
    9891003    return true;
    9901004}
    9911005
     1006/**
     1007 *  \brief Insert Callback function when Allow Re-record is pressed in Watch Recordings
     1008 */
    9921009uint DBEvent::InsertDB(MSqlQuery &query, uint chanid) const
    9931010{
    9941011    query.prepare(
    9951012        "REPLACE INTO program ("
    996         "  chanid,         title,          subtitle,        description, "
     1013        "  chanid,         title,          sorttitle, "
     1014        "  subtitle,       sortsubtitle,   description, "
    9971015        "  category,       category_type, "
    9981016        "  starttime,      endtime, "
    9991017        "  closecaptioned, stereo,         hdtv,            subtitled, "
    uint DBEvent::InsertDB(MSqlQuery &query, uint chanid) const  
    10051023        "  season,         episode,        totalepisodes, "
    10061024        "  inetref ) "
    10071025        "VALUES ("
    1008         " :CHANID,        :TITLE,         :SUBTITLE,       :DESCRIPTION, "
     1026        " :CHANID,        :TITLE,         :SORTTITLE, "
     1027        " :SUBTITLE,      :SORTSUBTITLE,  :DESCRIPTION, "
    10091028        " :CATEGORY,      :CATTYPE, "
    10101029        " :STARTTIME,     :ENDTIME, "
    10111030        " :CC,            :STEREO,        :HDTV,           :HASSUBTITLES, "
    uint DBEvent::InsertDB(MSqlQuery &query, uint chanid) const  
    10211040    QString empty("");
    10221041    query.bindValue(":CHANID",      chanid);
    10231042    query.bindValue(":TITLE",       denullify(title));
     1043    query.bindValue(":SORTTITLE",   denullify(sortTitle));
    10241044    query.bindValue(":SUBTITLE",    denullify(subtitle));
     1045    query.bindValue(":SORTSUBTITLE", denullify(sortSubtitle));
    10251046    query.bindValue(":DESCRIPTION", denullify(description));
    10261047    query.bindValue(":CATEGORY",    denullify(category));
    10271048    query.bindValue(":CATTYPE",     cattype);
    void ProgInfo::Squeeze(void)  
    11291150    clumpmax.squeeze();
    11301151}
    11311152
     1153/**
     1154 *  \brief Insert a single entry into the "program" database.
     1155 *
     1156 *  This function is called from HandlePrograms, which is called from
     1157 *  mythfilldatabase. It inserts a single entry into the "program"
     1158 *  database. The data for this structure is taken from the 'this'
     1159 *  ProgInfo object.
     1160 *
     1161 *  \param query  Any mysql query structure. The contents is ignored
     1162 *                and the structure is repurposed for local queries.
     1163 *  \param chanid The channel number for this program.
     1164 */
    11321165uint ProgInfo::InsertDB(MSqlQuery &query, uint chanid) const
    11331166{
    11341167    LOG(VB_XMLTV, LOG_INFO,
    uint ProgInfo::InsertDB(MSqlQuery &query, uint chanid) const  
    11401173
    11411174    query.prepare(
    11421175        "REPLACE INTO program ("
    1143         "  chanid,         title,          subtitle,        description, "
     1176        "  chanid,         title,          sorttitle, "
     1177        "  subtitle,       sortsubtitle,   description, "
    11441178        "  category,       category_type,  "
    11451179        "  starttime,      endtime, "
    11461180        "  closecaptioned, stereo,         hdtv,            subtitled, "
    uint ProgInfo::InsertDB(MSqlQuery &query, uint chanid) const  
    11541188        "  inetref ) "
    11551189
    11561190        "VALUES("
    1157         " :CHANID,        :TITLE,         :SUBTITLE,       :DESCRIPTION, "
     1191        " :CHANID,        :TITLE,         :SORTTITLE, "
     1192        " :SUBTITLE,      :SORTSUBTITLE,  :DESCRIPTION, "
    11581193        " :CATEGORY,      :CATTYPE,       "
    11591194        " :STARTTIME,     :ENDTIME, "
    11601195        " :CC,            :STEREO,        :HDTV,           :HASSUBTITLES, "
    uint ProgInfo::InsertDB(MSqlQuery &query, uint chanid) const  
    11691204
    11701205    QString cattype = myth_category_type_to_string(categoryType);
    11711206
     1207    // Someday mythfilldatabase might pass in sort strings. Until
     1208    // then, generate the sort strings here as needed.
     1209    SortHelper *sh = new SortHelper;
     1210    QString ltitle = denullify(title);
     1211    QString lsortTitle = denullify(sortTitle);
     1212    QString lsubtitle = denullify(subtitle);
     1213    QString lsortSubtitle = denullify(sortSubtitle);
     1214    if (lsortTitle.isEmpty())
     1215        lsortTitle = sh->doTitle(ltitle);
     1216    if (lsortSubtitle.isEmpty())
     1217        lsortSubtitle = sh->doTitle(lsubtitle);
     1218
    11721219    query.bindValue(":CHANID",      chanid);
    1173     query.bindValue(":TITLE",       denullify(title));
    1174     query.bindValue(":SUBTITLE",    denullify(subtitle));
     1220    query.bindValue(":TITLE",       ltitle);
     1221    query.bindValue(":SORTTITLE",   lsortTitle);
     1222    query.bindValue(":SUBTITLE",    lsubtitle);
     1223    query.bindValue(":SORTSUBTITLE", lsortSubtitle);
    11751224    query.bindValue(":DESCRIPTION", denullify(description));
    11761225    query.bindValue(":CATEGORY",    denullify(category));
    11771226    query.bindValue(":CATTYPE",     cattype);
    void ProgramData::FixProgramList(QList<ProgInfo*> &fixlist)  
    13741423    }
    13751424}
    13761425
     1426/**
     1427 *  \brief Called from mythfilldatabase to bulk insert data into the
     1428 *  program database.
     1429 *
     1430 *  \param sourceid The data source identifier
     1431 *  \param proglist A map of all program information keyed by channel
     1432 *                  identifier
     1433 */
    13771434void ProgramData::HandlePrograms(
    13781435    uint sourceid, QMap<QString, QList<ProgInfo> > &proglist)
    13791436{
    void ProgramData::HandlePrograms(  
    14321489                .arg(updated) .arg(unchanged));
    14331490}
    14341491
     1492/**
     1493 *  \brief Called from HandlePrograms to bulk insert data into the
     1494 *  program database.
     1495 *
     1496 *  \param query A mysql query related to all channel ids for
     1497 *               a given source
     1498 *  \param chanid The specific channel id to process
     1499 *  \param sortlist A time sorted list of ProgInfo structures
     1500 *  \param unchanged Set to the number of unchanged programs
     1501 *  \param updated Set to the number of updated programs
     1502 */
    14351503void ProgramData::HandlePrograms(MSqlQuery             &query,
    14361504                                 uint                   chanid,
    14371505                                 const QList<ProgInfo*> &sortlist,
  • mythtv/libs/libmythtv/programdata.h

    diff --git a/mythtv/libs/libmythtv/programdata.h b/mythtv/libs/libmythtv/programdata.h
    index 58db39b..9ee40a4 100644
    a b using namespace std;  
    2020#include "listingsources.h"
    2121#include "programinfo.h"
    2222#include "eithelper.h" /* for FixupValue */
     23#include "mythsorthelper.h"
    2324
    2425class MSqlQuery;
    2526
    class MTV_PUBLIC DBEvent  
    7576  public:
    7677    DBEvent(uint _listingsource) :
    7778        title(),
     79        sortTitle(),
    7880        subtitle(),
     81        sortSubtitle(),
    7982        description(),
    8083        category(),
    8184        /*starttime, endtime,*/
    class MTV_PUBLIC DBEvent  
    98101        episode(0),
    99102        totalepisodes(0) {}
    100103
    101     DBEvent(const QString   &_title,     const QString   &_subtitle,
     104    DBEvent(const QString   &_title,     const QString   &_sortTitle,
     105            const QString   &_subtitle,  const QString   &_sortSubtitle,
    102106            const QString   &_desc,
    103107            const QString   &_category,  ProgramInfo::CategoryType _category_type,
    104108            const QDateTime &_start,     const QDateTime &_end,
    class MTV_PUBLIC DBEvent  
    110114            uint32_t         _listingsource,
    111115            uint _season,                uint _episode,
    112116            uint _totalepisodes ) :
    113         title(_title),           subtitle(_subtitle),
     117        title(_title),           sortTitle(_sortTitle),
     118        subtitle(_subtitle),     sortSubtitle(_sortSubtitle),
    114119        description(_desc),
    115120        category(_category),
    116121        starttime(_start),       endtime(_end),
    class MTV_PUBLIC DBEvent  
    131136        episode(_episode),
    132137        totalepisodes(_totalepisodes)
    133138    {
     139        SortHelper *sh = new SortHelper;
     140        if (sortTitle.isEmpty())
     141            sortTitle = sh->doTitle(_title);
     142        if (sortSubtitle.isEmpty())
     143            sortSubtitle = sh->doTitle(_sortTitle);
    134144    }
    135145
    136146    virtual ~DBEvent() { delete credits; }
    class MTV_PUBLIC DBEvent  
    161171
    162172  public:
    163173    QString       title;
     174    QString       sortTitle;
    164175    QString       subtitle;
     176    QString       sortSubtitle;
    165177    QString       description;
    166178    QString       category;
    167179    QDateTime     starttime;
    class MTV_PUBLIC DBEventEIT : public DBEvent  
    193205{
    194206  public:
    195207    DBEventEIT(uint             _chanid,
    196                const QString   &_title,     const QString   &_subtitle,
     208               const QString   &_title,     const QString   &_sortTitle,
     209               const QString   &_subtitle,  const QString   &_sortSubtitle,
    197210               const QString   &_desc,
    198211               const QString   &_category,  ProgramInfo::CategoryType _category_type,
    199212               const QDateTime &_start,     const QDateTime &_end,
    class MTV_PUBLIC DBEventEIT : public DBEvent  
    205218               const QString   &_seriesId,  const QString   &_programId,
    206219               uint _season,                uint _episode,
    207220               uint _totalepisodes ) :
    208         DBEvent(_title, _subtitle, _desc, _category, _category_type,
     221        DBEvent(_title, _sortTitle, _subtitle, _sortSubtitle,
     222                _desc, _category, _category_type,
    209223                _start, _end, _subtitleType, _audioProps, _videoProps,
    210224                _stars, _seriesId, _programId, kListingSourceEIT,
    211225                _season, _episode, _totalepisodes),
    class MTV_PUBLIC DBEventEIT : public DBEvent  
    220234               unsigned char    _subtitleType,
    221235               unsigned char    _audioProps,
    222236               unsigned char    _videoProps) :
    223         DBEvent(_title, QString(), _desc, QString(), ProgramInfo::kCategoryNone,
     237        DBEvent(_title, QString(), QString(), QString(),
     238                _desc, QString(), ProgramInfo::kCategoryNone,
    224239                _start, _end, _subtitleType, _audioProps, _videoProps,
    225240                0.0, QString(), QString(), kListingSourceEIT, 0, 0, 0), // Season, Episode and Total Episodes are not set with this constructor!
    226241        chanid(_chanid), fixup(_fixup)
  • mythtv/libs/libmythtv/recordinginfo.cpp

    diff --git a/mythtv/libs/libmythtv/recordinginfo.cpp b/mythtv/libs/libmythtv/recordinginfo.cpp
    index 3a87da0..da1cec0 100644
    a b  
    1818#include "jobqueue.h"
    1919#include "mythdb.h"
    2020#include "mythlogging.h"
     21#include "mythsorthelper.h"
    2122
    2223#define LOC      QString("RecordingInfo(%1): ").arg(GetBasename())
    2324
    static const uint kUnknownProgramLength = 30;  
    3233
    3334RecordingInfo::RecordingInfo(
    3435    const QString &_title,
     36    const QString &_sortTitle,
    3537    const QString &_subtitle,
     38    const QString &_sortSubtitle,
    3639    const QString &_description,
    3740    uint _season,
    3841    uint _episode,
    RecordingInfo::RecordingInfo(  
    9598    uint _mplexid,
    9699    uint _sgroupid) :
    97100    ProgramInfo(
    98         _title, _subtitle, _description, _season, _episode, _totalepisodes,
     101        _title, _sortTitle, _subtitle, _sortSubtitle,
     102        _description, _season, _episode, _totalepisodes,
    99103        _category, _chanid, _chanstr, _chansign, _channame,
    100104        QString(), _recgroup, _playgroup,
    101105        _startts, _endts, _recstartts, _recendts,
    RecordingInfo::RecordingInfo(  
    162166
    163167RecordingInfo::RecordingInfo(
    164168    const QString &_title,
     169    const QString &_sortTitle,
    165170    const QString &_subtitle,
     171    const QString &_sortSubtitle,
    166172    const QString &_description,
    167173    uint _season,
    168174    uint _episode,
    RecordingInfo::RecordingInfo(  
    198204
    199205    bool _commfree) :
    200206    ProgramInfo(
    201         _title, _subtitle, _description, _season, _episode, 0,
     207        _title, _sortTitle, _subtitle, _sortSubtitle,
     208        _description, _season, _episode, 0,
    202209        _category, _chanid, _chanstr, _chansign, _channame,
    203210        QString(), _recgroup, _playgroup,
    204211        _startts, _endts, _recstartts, _recendts,
    void RecordingInfo::ApplyRecordRecTitleChange(const QString &newTitle,  
    755762        const QString &newSubtitle, const QString &newDescription)
    756763{
    757764    MSqlQuery query(MSqlQuery::InitCon());
    758     QString sql = "UPDATE recorded SET title = :TITLE, subtitle = :SUBTITLE ";
     765    QString sql = "UPDATE recorded SET "
     766        "    title = :TITLE, sorttitle = :SORTTITLE, "
     767        "    subtitle = :SUBTITLE, sortsubtitle = :SORTSUBTITLE ";
    759768    if (!newDescription.isNull())
    760769        sql += ", description = :DESCRIPTION ";
    761770    sql += " WHERE chanid = :CHANID AND starttime = :START ;";
    762771
     772    SortHelper *sh = new SortHelper;
    763773    query.prepare(sql);
    764774    query.bindValue(":TITLE", newTitle);
     775    query.bindValue(":SORTTITLE", sh->doTitle(newTitle));
    765776    query.bindValue(":SUBTITLE", null_to_empty(newSubtitle));
     777    query.bindValue(":SORTSUBTITLE", sh->doTitle(null_to_empty(newSubtitle)));
    766778    if (!newDescription.isNull())
    767779        query.bindValue(":DESCRIPTION", newDescription);
    768780    query.bindValue(":CHANID", chanid);
    bool RecordingInfo::InsertProgram(RecordingInfo *pg,  
    10451057
    10461058    query.prepare(
    10471059        "INSERT INTO recorded "
    1048         "   (chanid,    starttime,   endtime,         title,            "
    1049         "    subtitle,  description, season,          episode,          "
     1060        "   (chanid,    starttime,   endtime,                           "
     1061        "    title,     sorttitle,   subtitle,        sortsubtitle,     "
     1062        "               description, season,          episode,          "
    10501063        "    hostname,  category,    recgroup,        autoexpire,       "
    10511064        "    recordid,  seriesid,    programid,       inetref,          "
    10521065        "    stars,     previouslyshown,              originalairdate,  "
    bool RecordingInfo::InsertProgram(RecordingInfo *pg,  
    10541067        "    basename,  progstart,   progend,         profile,          "
    10551068        "    duplicate, storagegroup, inputname,      recgroupid) "
    10561069        "VALUES"
    1057         "  (:CHANID,   :STARTS,     :ENDS,           :TITLE,            "
    1058         "   :SUBTITLE, :DESC,       :SEASON,         :EPISODE,          "
     1070        "  (:CHANID,   :STARTS,     :ENDS,                              "
     1071        "   :TITLE,    :SORTTITLE,  :SUBTITLE,       :SORTSUBTITLE,     "
     1072        "              :DESC,       :SEASON,         :EPISODE,          "
    10591073        "   :HOSTNAME, :CATEGORY,   :RECGROUP,       :AUTOEXP,          "
    10601074        "   :RECORDID, :SERIESID,   :PROGRAMID,      :INETREF,          "
    10611075        "   :STARS,    :REPEAT,                      :ORIGAIRDATE,      "
    bool RecordingInfo::InsertProgram(RecordingInfo *pg,  
    10781092    query.bindValue(":STARTS",      pg->recstartts);
    10791093    query.bindValue(":ENDS",        pg->recendts);
    10801094    query.bindValue(":TITLE",       pg->title);
     1095    query.bindValue(":SORTTITLE",   pg->sortTitle);
    10811096    query.bindValue(":SUBTITLE",    null_to_empty(pg->subtitle));
     1097    query.bindValue(":SORTSUBTITLE", null_to_empty(pg->sortSubtitle));
    10821098    query.bindValue(":DESC",        null_to_empty(pg->description));
    10831099    query.bindValue(":SEASON",      pg->season);
    10841100    query.bindValue(":EPISODE",     pg->episode);
    void RecordingInfo::AddHistory(bool resched, bool forcedup, bool future)  
    12521268    result.prepare("REPLACE INTO oldrecorded (chanid,starttime,"
    12531269                   "endtime,title,subtitle,description,season,episode,"
    12541270                   "category,seriesid,programid,inetref,findid,recordid,"
    1255                    "station,rectype,recstatus,duplicate,reactivate,future) "
     1271                   "station,rectype,recstatus,duplicate,reactivate,future,"
     1272                   "sorttitle,sortsubtitle) "
    12561273                   "VALUES(:CHANID,:START,:END,:TITLE,:SUBTITLE,:DESC,:SEASON,"
    12571274                   ":EPISODE,:CATEGORY,:SERIESID,:PROGRAMID,:INETREF,"
    12581275                   ":FINDID,:RECORDID,:STATION,:RECTYPE,:RECSTATUS,:DUPLICATE,"
    1259                    ":REACTIVATE,:FUTURE);");
     1276                   ":REACTIVATE,:FUTURE,:SORTTITLE,:SORTSUBTITLE);");
    12601277    result.bindValue(":CHANID", chanid);
    12611278    result.bindValue(":START", startts);
    12621279    result.bindValue(":END", endts);
    12631280    result.bindValue(":TITLE", title);
     1281    result.bindValue(":SORTTITLE", sortTitle);
    12641282    result.bindValue(":SUBTITLE", null_to_empty(subtitle));
     1283    result.bindValue(":SORTSUBTITLE", null_to_empty(sortSubtitle));
    12651284    result.bindValue(":DESC", null_to_empty(description));
    12661285    result.bindValue(":SEASON", season);
    12671286    result.bindValue(":EPISODE", episode);
  • mythtv/libs/libmythtv/recordinginfo.h

    diff --git a/mythtv/libs/libmythtv/recordinginfo.h b/mythtv/libs/libmythtv/recordinginfo.h
    index 9502001..c2b4252 100644
    a b class MTV_PUBLIC RecordingInfo : public ProgramInfo  
    110110    /// used in scheduler.cpp @ ~ 3296
    111111    RecordingInfo(
    112112        const QString &title,
     113        const QString &sortTitle,
    113114        const QString &subtitle,
     115        const QString &sortSubtitle,
    114116        const QString &description,
    115117        uint season,
    116118        uint episode,
    class MTV_PUBLIC RecordingInfo : public ProgramInfo  
    177179    /// user in scheduler.cpp  @ ~ 3566 & ~ 3643
    178180    RecordingInfo(
    179181        const QString &title,
     182        const QString &sortTitle,
    180183        const QString &subtitle,
     184        const QString &sortSubtitle,
    181185        const QString &description,
    182186        uint season,
    183187        uint episode,
  • mythtv/libs/libmythtv/recordingrule.cpp

    diff --git a/mythtv/libs/libmythtv/recordingrule.cpp b/mythtv/libs/libmythtv/recordingrule.cpp
    index a206500..d9508b1 100644
    a b  
    1212#include "playgroup.h" // For GetInitialName()
    1313#include "recordingprofile.h" // For constants
    1414#include "mythdate.h"
     15#include "mythsorthelper.h"
    1516
    1617static inline QString null_to_empty(const QString &str)
    1718{
    bool RecordingRule::Load(bool asTemplate)  
    9394    "autometadata, parentid, title, subtitle, description, season, episode, "
    9495    "category, starttime, startdate, endtime, enddate, seriesid, programid, "
    9596    "inetref, chanid, station, findday, findtime, findid, "
    96     "next_record, last_record, last_delete, avg_delay, filter, recgroupid "
     97    "next_record, last_record, last_delete, avg_delay, filter, recgroupid, "
     98    "sorttitle,sortsubtitle "
    9799    "FROM record WHERE recordid = :RECORDID ;");
    98100
    99101    query.bindValue(":RECORDID", m_recordID);
    bool RecordingRule::Load(bool asTemplate)  
    150152    if (!asTemplate)
    151153    {
    152154        m_title = query.value(25).toString();
     155        m_sortTitle = query.value(49).toString();
    153156        m_subtitle = query.value(26).toString();
     157        m_sortSubtitle = query.value(50).toString();
    154158        m_description = query.value(27).toString();
    155159        m_season = query.value(28).toUInt();
    156160        m_episode = query.value(29).toUInt();
    bool RecordingRule::LoadBySearch(RecSearchType lsearch, QString textname,  
    258262        m_searchType = lsearch;
    259263        searchType = SearchTypeToString(m_searchType);
    260264
     265        SortHelper *sh = new SortHelper;
    261266        QString ltitle = QString("%1 (%2)").arg(textname).arg(searchType);
    262267        m_title = ltitle;
     268        m_sortTitle = sh->doTitle(ltitle);
     269        // The caller from customedit.cpp calls here with the subtitle
     270        // in the 'from' argument. The other callers from
     271        // proglist_helpers.cpp call with an SQL code fragment in the
     272        // 'from' field. Impossible to know what's the right way to
     273        // create the sortSubtitle field.
    263274        m_subtitle = from;
     275        m_sortSubtitle = from;
    264276        m_description = forwhat;
    265277
    266278        if (pginfo)
    bool RecordingRule::MakeTemplate(QString category)  
    322334    {
    323335        category = "Default";
    324336        m_title = tr("Default (Template)");
     337        m_sortTitle = m_title;
    325338    }
    326339    else
    327340    {
    328341        //: %1 is the category
    329342        m_title = tr("%1 (Template)").arg(category);
     343        m_sortTitle = m_title;
    330344    }
    331345
    332346    LoadTemplate(category);
    bool RecordingRule::ModifyPowerSearchByID(int rid, QString textname,  
    351365
    352366    QString ltitle = QString("%1 (%2)").arg(textname)
    353367                                       .arg(tr("Power Search"));
     368    SortHelper *sh = new SortHelper;
    354369    m_title = ltitle;
     370    m_sortTitle = sh->doTitle(ltitle);
    355371    m_subtitle = from;
     372    // This doesn't appear to be a subtitle, so copy it verbatim.
     373    m_sortSubtitle = from;
    356374    m_description = forwhat;
    357375
    358376    m_loaded = true;
    bool RecordingRule::Save(bool sendSig)  
    401419                    "autouserjob3 = :AUTOUSERJOB3, "
    402420                    "autouserjob4 = :AUTOUSERJOB4, "
    403421                    "autometadata = :AUTOMETADATA, "
    404                     "parentid = :PARENTID, title = :TITLE, "
    405                     "subtitle = :SUBTITLE, season = :SEASON, episode = :EPISODE, "
     422                    "parentid = :PARENTID, "
     423                    "title = :TITLE, sorttitle = :SORTTITLE, "
     424                    "subtitle = :SUBTITLE, sortsubtitle = :SORTSUBTITLE, "
     425                    "season = :SEASON, episode = :EPISODE, "
    406426                    "description = :DESCRIPTION, category = :CATEGORY, "
    407427                    "starttime = :STARTTIME, startdate = :STARTDATE, "
    408428                    "endtime = :ENDTIME, enddate = :ENDDATE, seriesid = :SERIESID, "
    bool RecordingRule::Save(bool sendSig)  
    450470    query.bindValue(":AUTOMETADATA", m_autoMetadataLookup);
    451471    query.bindValue(":PARENTID", m_parentRecID);
    452472    query.bindValue(":TITLE", m_title);
     473    query.bindValue(":SORTTITLE", m_sortTitle);
    453474    query.bindValue(":SUBTITLE", null_to_empty(m_subtitle));
     475    query.bindValue(":SORTSUBTITLE", null_to_empty(m_sortSubtitle));
    454476    query.bindValue(":DESCRIPTION", null_to_empty(m_description));
    455477    query.bindValue(":SEASON", m_season);
    456478    query.bindValue(":EPISODE", m_episode);
    bool RecordingRule::Delete(bool sendSig)  
    542564void RecordingRule::ToMap(InfoMap &infoMap) const
    543565{
    544566    if (m_title == "Default (Template)")
     567    {
    545568        infoMap["title"] = tr("Default (Template)");
     569        infoMap["sorttitle"] = tr("Default (Template)");
     570    }
    546571    else
     572    {
    547573        infoMap["title"] = m_title;
     574        infoMap["sorttitle"] = m_sortTitle;
     575    }
    548576    infoMap["subtitle"] = m_subtitle;
     577    infoMap["sortsubtitle"] = m_sortSubtitle;
    549578    infoMap["description"] = m_description;
    550579    infoMap["season"] = QString::number(m_season);
    551580    infoMap["episode"] = QString::number(m_episode);
    void RecordingRule::AssignProgramInfo()  
    736765        return;
    737766
    738767    m_title       = m_progInfo->GetTitle();
     768    m_sortTitle   = m_progInfo->GetSortTitle();
    739769    m_subtitle    = m_progInfo->GetSubtitle();
     770    m_sortSubtitle= m_progInfo->GetSortSubtitle();
    740771    m_description = m_progInfo->GetDescription();
    741772    m_channelid   = m_progInfo->GetChanID();
    742773    m_station     = m_progInfo->GetChannelSchedulingID();
  • mythtv/libs/libmythtv/recordingrule.h

    diff --git a/mythtv/libs/libmythtv/recordingrule.h b/mythtv/libs/libmythtv/recordingrule.h
    index 0ef9c5a..4e10ac0 100644
    a b class MTV_PUBLIC RecordingRule  
    7373
    7474    // Recording metadata
    7575    QString m_title;
     76    QString m_sortTitle;
    7677    QString m_subtitle;
     78    QString m_sortSubtitle;
    7779    QString m_description;
    7880    uint m_season;
    7981    uint m_episode;
  • mythtv/libs/libmythtv/test/test_eitfixups/test_eitfixups.cpp

    diff --git a/mythtv/libs/libmythtv/test/test_eitfixups/test_eitfixups.cpp b/mythtv/libs/libmythtv/test/test_eitfixups/test_eitfixups.cpp
    index 946a5f7..e9f6f76 100644
    a b DBEventEIT *TestEITFixups::SimpleDBEventEIT (FixupValue fixup, QString title, QS  
    419419{
    420420    DBEventEIT *event = new DBEventEIT (1, // channel id
    421421                                       title, // title
     422                                       QString(), //sortTitle
    422423                                       subtitle, // subtitle
     424                                       QString(), //sortSubtitle
    423425                                       description, // description
    424426                                       "", // category
    425427                                       ProgramInfo::kCategoryNone, // category_type
  • mythtv/programs/mythbackend/main_helpers.cpp

    diff --git a/mythtv/programs/mythbackend/main_helpers.cpp b/mythtv/programs/mythbackend/main_helpers.cpp
    index e4a4089..bb698af 100644
    a b int run_backend(MythBackendCommandLineParser &cmdline)  
    568568
    569569    if (!UpgradeTVDatabaseSchema(ismaster, ismaster))
    570570    {
    571         LOG(VB_GENERAL, LOG_ERR, "Couldn't upgrade database to new schema");
     571        if (ismaster)
     572            LOG(VB_GENERAL, LOG_ERR, "Couldn't upgrade database to new schema on master backend.");
     573        else
     574            LOG(VB_GENERAL, LOG_ERR, "Couldn't upgrade database to new schema on slave backend.");
    572575        return GENERIC_EXIT_DB_OUTOFDATE;
    573576    }
    574577
  • mythtv/programs/mythbackend/scheduler.cpp

    diff --git a/mythtv/programs/mythbackend/scheduler.cpp b/mythtv/programs/mythbackend/scheduler.cpp
    index 49b2912..e39eb73 100644
    a b void Scheduler::UpdateManuals(uint recordid)  
    36663666    MSqlQuery query(dbConn);
    36673667
    36683668    query.prepare(QString("SELECT type,title,station,startdate,starttime, "
    3669                   " enddate,endtime "
     3669                  " enddate,endtime,sorttitle "
    36703670                  "FROM %1 WHERE recordid = :RECORDID").arg(recordTable));
    36713671    query.bindValue(":RECORDID", recordid);
    36723672    if (!query.exec() || query.size() != 1)
    void Scheduler::UpdateManuals(uint recordid)  
    36803680
    36813681    RecordingType rectype = RecordingType(query.value(0).toInt());
    36823682    QString title = query.value(1).toString();
     3683    QString sortTitle = query.value(7).toString();
    36833684    QString station = query.value(2).toString() ;
    36843685    QDateTime startdt = QDateTime(query.value(3).toDate(),
    36853686                                  query.value(4).toTime(), Qt::UTC);
    void Scheduler::UpdateManuals(uint recordid)  
    37493750                continue;
    37503751
    37513752            query.prepare("REPLACE INTO program (chanid, starttime, endtime,"
    3752                           " title, subtitle, manualid, generic) "
     3753                          " title, sorttitle, subtitle, manualid, generic) "
    37533754                          "VALUES (:CHANID, :STARTTIME, :ENDTIME, :TITLE,"
    3754                           " :SUBTITLE, :RECORDID, 1)");
     3755                          " :SORTTITLE, :SUBTITLE, :RECORDID, 1)");
    37553756            query.bindValue(":CHANID", chanidlist[i]);
    37563757            query.bindValue(":STARTTIME", startdt);
    37573758            query.bindValue(":ENDTIME", startdt.addSecs(duration));
    37583759            query.bindValue(":TITLE", title);
     3760            query.bindValue(":SORTTITLE", sortTitle);
    37593761            query.bindValue(":SUBTITLE", startdt.toLocalTime());
    37603762            query.bindValue(":RECORDID", recordid);
    37613763            if (!query.exec())
    void Scheduler::AddNewRecords(void)  
    44394441        "    capturecard.hostname, recordmatch.oldrecstatus, NULL, "//43-45
    44404442        "    oldrecstatus.future, capturecard.schedorder, " //46-47
    44414443        "    p.syndicatedepisodenumber, p.partnumber, p.parttotal, " //48-50
    4442         "    c.mplexid, ") +                                         //51
     4444        "    c.mplexid, p.sorttitle, p.sortsubtitle, ") +            //51-53
    44434445        pwrpri + QString(
    44444446        "FROM recordmatch "
    44454447        "INNER JOIN RECTABLE ON (recordmatch.recordid = RECTABLE.recordid) "
    void Scheduler::AddNewRecords(void)  
    45064508
    45074509        RecordingInfo *p = new RecordingInfo(
    45084510            title,
     4511            result.value(52).toString(),//sorttitle
    45094512            result.value(5).toString(),//subtitle
     4513            result.value(53).toString(),//sortsubtitle
    45104514            result.value(6).toString(),//description
    45114515            0, // season
    45124516            0, // episode
    void Scheduler::AddNotListed(void) {  
    47094713        "       RECTABLE.dupin,       RECTABLE.dupmethod,   " // 22,23
    47104714        "       RECTABLE.findid,                            " // 24
    47114715        "       RECTABLE.startoffset, RECTABLE.endoffset,   " // 25,26
    4712         "       channel.commmethod                          " // 27
     4716        "       channel.commmethod,   RECTABLE.sorttitle,   " // 27,28
     4717        "       RECTABLE.sortsubtitle                       " // 29
    47134718        "FROM RECTABLE "
    47144719        "INNER JOIN channel ON (channel.chanid = RECTABLE.chanid) "
    47154720        "LEFT JOIN recordmatch on RECTABLE.recordid = recordmatch.recordid "
    void Scheduler::AddNotListed(void) {  
    47684773
    47694774        RecordingInfo *p = new RecordingInfo(
    47704775            result.value(0).toString(), // Title
     4776            result.value(28).toString(), // Title Sort
    47714777            (sor) ? result.value(1).toString() : QString(), // Subtitle
     4778            (sor) ? result.value(29).toString() : QString(), // Subtitle Sort
    47724779            (sor) ? result.value(2).toString() : QString(), // Description
    47734780            result.value(3).toUInt(), // Season
    47744781            result.value(4).toUInt(), // Episode
    void Scheduler::GetAllScheduled(RecList &proglist, SchedSortColumn sortBy,  
    48654872        "       record.recordid,    record.type,        " // 20,21
    48664873        "       record.dupin,       record.dupmethod,   " // 22,23
    48674874        "       record.findid,                          " // 24
    4868         "       channel.commmethod                      " // 25
     4875        "       channel.commmethod,                     " // 25
     4876        "       record.sorttitle,   record.sortsubtitle " // 26,27
    48694877        "FROM record "
    48704878        "LEFT JOIN channel ON channel.callsign = record.station "
    48714879        "GROUP BY recordid "
    void Scheduler::GetAllScheduled(RecList &proglist, SchedSortColumn sortBy,  
    48974905            endts = startts;
    48984906
    48994907        proglist.push_back(new RecordingInfo(
    4900             result.value(0).toString(),  result.value(1).toString(),
     4908            result.value(0).toString(),  result.value(26).toString(),
     4909            result.value(1).toString(),  result.value(27).toString(),
    49014910            result.value(2).toString(),  result.value(3).toUInt(),
    49024911            result.value(4).toUInt(),    result.value(5).toString(),
    49034912
  • mythtv/programs/mythbackend/services/video.cpp

    diff --git a/mythtv/programs/mythbackend/services/video.cpp b/mythtv/programs/mythbackend/services/video.cpp
    index 7f977c2..00c4305 100644
    a b bool Video::AddVideo( const QString &sFileName,  
    347347        hash = "";
    348348    }
    349349
    350     VideoMetadata newFile(sFileName, hash,
     350    VideoMetadata newFile(sFileName, QString(), hash,
    351351                          VIDEO_TRAILER_DEFAULT,
    352352                          VIDEO_COVERFILE_DEFAULT,
    353353                          VIDEO_SCREENSHOT_DEFAULT,
    354354                          VIDEO_BANNER_DEFAULT,
    355355                          VIDEO_FANART_DEFAULT,
    356                           VideoMetadata::FilenameToMeta(sFileName, 1),
    357                           VideoMetadata::FilenameToMeta(sFileName, 4),
     356                          QString(), QString(), QString(), QString(),
    358357                          QString(), VIDEO_YEAR_DEFAULT,
    359358                          QDate::fromString("0000-00-00","YYYY-MM-DD"),
    360359                          VIDEO_INETREF_DEFAULT, 0, QString(),
    361360                          VIDEO_DIRECTOR_DEFAULT, QString(), VIDEO_PLOT_DEFAULT,
    362361                          0.0, VIDEO_RATING_DEFAULT, 0, 0,
    363                           VideoMetadata::FilenameToMeta(sFileName, 2).toInt(),
    364                           VideoMetadata::FilenameToMeta(sFileName, 3).toInt(),
     362                          0, 0,
    365363                          MythDate::current().date(), 0,
    366364                          ParentalLevel::plLowest);
    367365
  • mythtv/programs/mythfrontend/globalsettings.cpp

    diff --git a/mythtv/programs/mythfrontend/globalsettings.cpp b/mythtv/programs/mythfrontend/globalsettings.cpp
    index 4e53990..78b7852 100644
    a b ChannelGroupSettings::ChannelGroupSettings() :  
    27562756    addTarget("1", new VerticalConfigurationGroup(true,false));
    27572757};
    27582758
     2759static HostCheckBox *SortIgnoreCase()
     2760{
     2761    HostCheckBox *gc = new HostCheckBox("SortIgnoreCase");
     2762    gc->setLabel(GeneralSettings::tr("Ignore case when sorting"));
     2763    gc->setValue(true);
     2764    gc->setHelpText(GeneralSettings::tr("If enabled, all sorting will be case-insensitive."));
     2765    return gc;
     2766}
     2767
     2768static HostCheckBox *SortIgnorePrefixes()
     2769{
     2770    HostCheckBox *gc = new HostCheckBox("SortIgnorePrefixes");
     2771
     2772    gc->setLabel(GeneralSettings::tr("Ignore prefixes when sorting"));
     2773    gc->setValue(true);
     2774    gc->setHelpText(GeneralSettings::tr("If enabled, video listings will "
     2775                                        "ignore common prefixes (The, A, An) when "
     2776                                        "sorting show names."));
     2777    return gc;
     2778}
     2779
     2780static HostLineEdit *SortIgnorePrefixExceptions()
     2781{
     2782    HostLineEdit *gc = new HostLineEdit("SortIgnorePrefixExceptions");
     2783
     2784    gc->setLabel(MainGeneralSettings::tr("Names exempt from prefix removal"));
     2785    gc->setValue("");
     2786    gc->setHelpText(MainGeneralSettings::tr("When stripping common prefixes (The, A, An) "
     2787                                            "from filenames, this list of names "
     2788                                            "will be exempt from that process. "
     2789                                            "Enter multiple names separated by ';'."));
     2790    return gc;
     2791}
     2792
     2793
    27592794// General RecPriorities settings
    27602795
    27612796static GlobalComboBox *GRSchedOpenEnd()
    MainGeneralSettings::MainGeneralSettings()  
    38633898    general->setLabel(tr("General"));
    38643899    general->addChild(UseVirtualKeyboard());
    38653900    general->addChild(ScreenShotPath());
     3901    general->addChild(SortIgnoreCase());
     3902    general->addChild(SortIgnorePrefixes());
     3903    general->addChild(SortIgnorePrefixExceptions());
    38663904    addChild(general);
    38673905
    38683906    VerticalConfigurationGroup *media =
  • mythtv/programs/mythfrontend/main.cpp

    diff --git a/mythtv/programs/mythfrontend/main.cpp b/mythtv/programs/mythfrontend/main.cpp
    index f4ed3f2..ef12639 100644
    a b static int internal_play_media(const QString &mrl, const QString &plot,  
    11681168    }
    11691169
    11701170    ProgramInfo *pginfo = new ProgramInfo(
    1171         mrl, plot, title, subtitle, director, season, episode,
    1172         inetref, lenMins, (year.toUInt()) ? year.toUInt() : 1900,
    1173         id);
     1171        mrl, plot, title, QString(), subtitle, QString(),
     1172        director, season, episode, inetref, lenMins,
     1173        (year.toUInt()) ? year.toUInt() : 1900, id);
    11741174
    11751175    pginfo->SetProgramInfoType(pginfo->DiscoverProgramInfoType());
    11761176
  • mythtv/programs/mythfrontend/playbackbox.cpp

    diff --git a/mythtv/programs/mythfrontend/playbackbox.cpp b/mythtv/programs/mythfrontend/playbackbox.cpp
    index fea8033..26427a4 100644
    a b static PlaybackBox::ViewMask m_viewMaskToggle(PlaybackBox::ViewMask mask,  
    222222
    223223static QString construct_sort_title(
    224224    QString title, PlaybackBox::ViewMask viewmask,
    225     PlaybackBox::ViewTitleSort titleSort, int recpriority,
    226     const QRegExp &prefixes)
     225    PlaybackBox::ViewTitleSort sortType, int recpriority)
    227226{
    228227    if (title.isEmpty())
    229228        return title;
    230229
    231230    QString sTitle = title;
    232231
    233     sTitle.remove(prefixes);
    234232    if (viewmask == PlaybackBox::VIEW_TITLES &&
    235             titleSort == PlaybackBox::TitleSortRecPriority)
     233            sortType == PlaybackBox::TitleSortRecPriority)
    236234    {
    237235        // Also incorporate recpriority (reverse numeric sort). In
    238236        // case different episodes of a recording schedule somehow
    void * PlaybackBox::RunPlaybackBox(void * player, bool showTV)  
    393391PlaybackBox::PlaybackBox(MythScreenStack *parent, QString name,
    394392                            TV *player, bool showTV)
    395393    : ScheduleCommon(parent, name),
    396       m_prefixes(QObject::tr("^(The |A |An )")),
    397394      m_titleChaff(" \\(.*\\)$"),
    398395      // UI variables
    399396      m_recgroupList(NULL),
    bool PlaybackBox::UpdateUILists(void)  
    17571754                    (pRecgroup != "LiveTV" || m_recGroup == "LiveTV"))
    17581755            {
    17591756                sTitle = construct_sort_title(
    1760                             p->GetTitle(), m_viewMask, titleSort,
    1761                             p->GetRecordingPriority(), m_prefixes);
     1757                            p->GetSortTitle(), m_viewMask, titleSort,
     1758                            p->GetRecordingPriority());
    17621759                sTitle = sTitle.toLower();
    17631760
    17641761                if (!sortedList.contains(sTitle))
  • mythtv/programs/mythfrontend/playbackbox.h

    diff --git a/mythtv/programs/mythfrontend/playbackbox.h b/mythtv/programs/mythfrontend/playbackbox.h
    index 6b7e144..07ee0e4 100644
    a b class PlaybackBox : public ScheduleCommon  
    338338    QString extract_commflag_state(const ProgramInfo &pginfo);
    339339
    340340
    341     QRegExp m_prefixes;   ///< prefixes to be ignored when sorting
    342341    QRegExp m_titleChaff; ///< stuff to remove for search rules
    343342
    344343    MythUIButtonList *m_recgroupList;
  • mythtv/programs/mythfrontend/proglist.cpp

    diff --git a/mythtv/programs/mythfrontend/proglist.cpp b/mythtv/programs/mythfrontend/proglist.cpp
    index ccdb95a..cb988c5 100644
    a b class plTitleSort : public plCompare  
    10571057  public:
    10581058    bool operator()(const ProgramInfo *a, const ProgramInfo *b)
    10591059    {
    1060         if (a->sortTitle != b->sortTitle)
    1061             return (a->sortTitle < b->sortTitle);
     1060        if (a->GetSortTitle() != b->GetSortTitle())
     1061            return (a->GetSortTitle() < b->GetSortTitle());
     1062        if (a->GetSortSubtitle() != b->GetSortSubtitle())
     1063            return (a->GetSortSubtitle() < b->GetSortSubtitle());
    10621064
    10631065        if (a->GetRecordingStatus() == b->GetRecordingStatus())
    10641066            return a->GetScheduledStartTime() < b->GetScheduledStartTime();
    class plPrevTitleSort : public plCompare  
    10901092
    10911093    bool operator()(const ProgramInfo *a, const ProgramInfo *b)
    10921094    {
    1093         if (a->sortTitle != b->sortTitle)
    1094             return (a->sortTitle < b->sortTitle);
     1095        if (a->GetSortTitle() != b->GetSortTitle())
     1096            return (a->GetSortTitle() < b->GetSortTitle());
     1097        if (a->GetSortSubtitle() != b->GetSortSubtitle())
     1098            return (a->GetSortSubtitle() < b->GetSortSubtitle());
    10951099
    10961100        if (a->GetProgramID() != b->GetProgramID())
    10971101            return a->GetProgramID() < b->GetProgramID();
    void ProgLister::FillItemList(bool restorePosition, bool updateDisp)  
    13901394        LoadFromProgram(m_itemList, where, bindings, m_schedList);
    13911395    }
    13921396
    1393     const QRegExp prefixes(
    1394         tr("^(The |A |An )",
    1395            "Regular Expression for what to ignore when sorting"));
    1396     for (uint i = 0; i < m_itemList.size(); i++)
    1397     {
    1398         ProgramInfo *s = m_itemList[i];
    1399         if (s)
    1400         {
    1401             s->sortTitle = (m_type == plTitle) ? s->GetSubtitle() : s->GetTitle();
    1402             s->sortTitle.remove(prefixes);
    1403         }
    1404     }
    1405 
    14061397    if (m_type == plNewListings || m_titleSort)
    14071398    {
    14081399        SortList(kTitleSort, m_reverseSort);
    void ProgLister::FillItemList(bool restorePosition, bool updateDisp)  
    14131404            ProgramList::iterator it = m_itemList.begin();
    14141405            while (it != m_itemList.end())
    14151406            {
    1416                 if ((*it)->sortTitle != curtitle)
     1407                if ((*it)->GetSortTitle() != curtitle)
    14171408                {
    1418                     curtitle = (*it)->sortTitle;
     1409                    curtitle = (*it)->GetSortTitle();
    14191410                    ++it;
    14201411                }
    14211412                else
  • mythtv/programs/mythfrontend/programrecpriority.cpp

    diff --git a/mythtv/programs/mythfrontend/programrecpriority.cpp b/mythtv/programs/mythfrontend/programrecpriority.cpp
    index dc8c5fd..923e658 100644
    a b class TitleSort  
    133133    bool operator()(const ProgramRecPriorityInfo *a,
    134134                    const ProgramRecPriorityInfo *b) const
    135135    {
    136         if (a->sortTitle != b->sortTitle)
     136        if (a->GetSortTitle() != b->GetSortTitle())
    137137        {
    138138            if (m_reverse)
    139                 return (a->sortTitle > b->sortTitle);
     139                return (a->GetSortTitle() > b->GetSortTitle());
    140140            else
    141                 return (a->sortTitle < b->sortTitle);
     141                return (a->GetSortTitle() < b->GetSortTitle());
     142        }
     143
     144        if (a->GetSortSubtitle() != b->GetSortSubtitle())
     145        {
     146            if (m_reverse)
     147                return (a->GetSortSubtitle() > b->GetSortSubtitle());
     148            else
     149                return (a->GetSortSubtitle() < b->GetSortSubtitle());
    142150        }
    143151
    144152        int finalA = a->GetRecordingPriority();
    class ProgramCountSort  
    288296                return recCountA > recCountB;
    289297        }
    290298
     299        if (a->GetSortTitle() != b->GetSortTitle())
     300        {
     301            if (m_reverse)
     302                return (a->GetSortTitle() > b->GetSortTitle());
     303            else
     304                return (a->GetSortTitle() < b->GetSortTitle());
     305        }
     306
    291307        if (m_reverse)
    292             return (a->sortTitle > b->sortTitle);
     308            return (a->GetSortSubtitle() > b->GetSortSubtitle());
    293309        else
    294             return (a->sortTitle < b->sortTitle);
     310            return (a->GetSortSubtitle() < b->GetSortSubtitle());
    295311    }
    296312
    297313  private:
    class ProgramRecCountSort  
    327343                return countA > countB;
    328344        }
    329345
     346        if (a->GetSortTitle() != b->GetSortTitle())
     347        {
     348            if (m_reverse)
     349                return (a->GetSortTitle() > b->GetSortTitle());
     350            else
     351                return (a->GetSortTitle() < b->GetSortTitle());
     352        }
     353
    330354        if (m_reverse)
    331             return (a->sortTitle > b->sortTitle);
     355            return (a->GetSortSubtitle() > b->GetSortSubtitle());
    332356        else
    333             return (a->sortTitle < b->sortTitle);
     357            return (a->GetSortSubtitle() < b->GetSortSubtitle());
    334358    }
    335359
    336360  private:
    class ProgramLastRecordSort  
    356380                return lastRecA > lastRecB;
    357381        }
    358382
     383        if (a->GetSortTitle() != b->GetSortTitle())
     384        {
     385            if (m_reverse)
     386                return (a->GetSortTitle() > b->GetSortTitle());
     387            else
     388                return (a->GetSortTitle() < b->GetSortTitle());
     389        }
     390
    359391        if (m_reverse)
    360             return (a->sortTitle > b->sortTitle);
     392            return (a->GetSortSubtitle() > b->GetSortSubtitle());
    361393        else
    362             return (a->sortTitle < b->sortTitle);
     394            return (a->GetSortSubtitle() < b->GetSortSubtitle());
    363395    }
    364396
    365397  private:
    class ProgramAvgDelaySort  
    385417                return avgA < avgB;
    386418        }
    387419
     420        if (a->GetSortTitle() != b->GetSortTitle())
     421        {
     422            if (m_reverse)
     423                return (a->GetSortTitle() > b->GetSortTitle());
     424            else
     425                return (a->GetSortTitle() < b->GetSortTitle());
     426        }
     427
    388428        if (m_reverse)
    389             return (a->sortTitle > b->sortTitle);
     429            return (a->GetSortSubtitle() > b->GetSortSubtitle());
    390430        else
    391             return (a->sortTitle < b->sortTitle);
     431            return (a->GetSortSubtitle() < b->GetSortSubtitle());
    392432    }
    393433
    394434  private:
    void ProgramRecPriority::scheduleChanged(int recid)  
    935975        ProgramRecPriorityInfo progInfo;
    936976        progInfo.SetRecordingRuleID(record.m_recordID);
    937977        progInfo.SetRecordingRuleType(record.m_type);
    938         progInfo.SetTitle(record.m_title);
     978        progInfo.SetTitle(record.m_title, record.m_sortTitle);
     979        progInfo.SetSubtitle(record.m_subtitle, record.m_sortSubtitle);
    939980        progInfo.SetCategory(record.m_category);
    940981        progInfo.SetRecordingPriority(record.m_recPriority);
    941982        progInfo.recType = record.m_type;
    942         progInfo.sortTitle = record.m_title;
    943983        progInfo.recstatus = record.m_isInactive ?
    944984            RecStatus::Inactive : RecStatus::Unknown;
    945985        progInfo.profile = record.m_recProfile;
    void ProgramRecPriority::FillList(void)  
    11771217    // it all at once than once per program)
    11781218
    11791219    MSqlQuery result(MSqlQuery::InitCon());
    1180     result.prepare("SELECT recordid, title, chanid, starttime, startdate, "
    1181                    "type, inactive, last_record, avg_delay, profile "
     1220    result.prepare("SELECT recordid, title, chanid, starttime, startdate, " // 0-4
     1221                   "type, inactive, last_record, avg_delay, profile, " // 5-9
     1222                   "subtitle, sorttitle, sortsubtitle " // 10-12
    11821223                   "FROM record;");
    11831224
    11841225    if (!result.exec())
    void ProgramRecPriority::FillList(void)  
    11911232        do {
    11921233            uint recordid = result.value(0).toUInt();
    11931234            QString title = result.value(1).toString();
     1235            QString sortTitle = result.value(10).toString();
     1236            QString subtitle = result.value(11).toString();
     1237            QString sortSubtitle = result.value(12).toString();
    11941238            QString chanid = result.value(2).toString();
    11951239            QString tempTime = result.value(3).toString();
    11961240            QString tempDate = result.value(4).toString();
    void ProgramRecPriority::FillList(void)  
    12081252            {
    12091253                ProgramRecPriorityInfo *progInfo = &(*it);
    12101254
    1211                 progInfo->sortTitle = progInfo->title;
    1212                 progInfo->sortTitle.remove(QRegExp(tr("^(The |A |An )")));
    1213 
    12141255                progInfo->recType = recType;
    12151256                progInfo->matchCount =
    12161257                    m_listMatch[progInfo->GetRecordingRuleID()];
  • mythtv/programs/mythfrontend/videofilter.cpp

    diff --git a/mythtv/programs/mythfrontend/videofilter.cpp b/mythtv/programs/mythfrontend/videofilter.cpp
    index 2e82927..86b9e0b 100644
    a b bool VideoFilterSettings::matches_filter(const VideoMetadata &mdata) const  
    389389
    390390/// Compares two VideoMetadata instances
    391391bool VideoFilterSettings::meta_less_than(const VideoMetadata &lhs,
    392                                          const VideoMetadata &rhs,
    393                                          bool sort_ignores_case) const
     392                                         const VideoMetadata &rhs) const
    394393{
    395394    bool ret = false;
    396395    switch (orderby)
    397396    {
    398397        case kOrderByTitle:
    399398        {
    400             VideoMetadata::SortKey lhs_key;
    401             VideoMetadata::SortKey rhs_key;
    402             if (lhs.HasSortKey() && rhs.HasSortKey())
    403             {
    404                 lhs_key = lhs.GetSortKey();
    405                 rhs_key = rhs.GetSortKey();
    406             }
    407             else
    408             {
    409                 lhs_key = VideoMetadata::GenerateDefaultSortKey(lhs,
    410                                                            sort_ignores_case);
    411                 rhs_key = VideoMetadata::GenerateDefaultSortKey(rhs,
    412                                                            sort_ignores_case);
    413             }
    414             ret = lhs_key < rhs_key;
     399            ret = lhs.sortBefore(rhs);
    415400            break;
    416401        }
    417402        case kOrderBySeasonEp:
    bool VideoFilterSettings::meta_less_than(const VideoMetadata &lhs,  
    423408                && (lhs.GetEpisode() == 0)
    424409                && (rhs.GetEpisode() == 0))
    425410            {
    426                 VideoMetadata::SortKey lhs_key;
    427                 VideoMetadata::SortKey rhs_key;
    428                 if (lhs.HasSortKey() && rhs.HasSortKey())
    429                 {
    430                     lhs_key = lhs.GetSortKey();
    431                     rhs_key = rhs.GetSortKey();
    432                 }
    433                 else
    434                 {
    435                     lhs_key = VideoMetadata::GenerateDefaultSortKey(lhs,
    436                                                                sort_ignores_case);
    437                     rhs_key = VideoMetadata::GenerateDefaultSortKey(rhs,
    438                                                                sort_ignores_case);
    439                 }
    440                 ret = lhs_key < rhs_key;
     411                ret = lhs.sortBefore(rhs);
    441412            }
    442413            else if ((lhs.GetSeason() == rhs.GetSeason())
    443414                     && (lhs.GetTitle() == rhs.GetTitle()))
    bool VideoFilterSettings::meta_less_than(const VideoMetadata &lhs,  
    463434        }
    464435        case kOrderByFilename:
    465436        {
    466             QString lhsfn(sort_ignores_case ?
    467                           lhs.GetFilename().toLower() : lhs.GetFilename());
    468             QString rhsfn(sort_ignores_case ?
    469                           rhs.GetFilename().toLower() : rhs.GetFilename());
     437            QString lhsfn = lhs.GetSortFilename();
     438            QString rhsfn = rhs.GetSortFilename();
    470439            ret = naturalCompare(lhsfn, rhsfn) < 0;
    471440            break;
    472441        }
  • mythtv/programs/mythfrontend/videofilter.h

    diff --git a/mythtv/programs/mythfrontend/videofilter.h b/mythtv/programs/mythfrontend/videofilter.h
    index d518abf..4a6a171 100644
    a b class VideoFilterSettings  
    4848    VideoFilterSettings &operator=(const VideoFilterSettings &rhs);
    4949
    5050    bool matches_filter(const VideoMetadata &mdata) const;
    51     bool meta_less_than(const VideoMetadata &lhs, const VideoMetadata &rhs,
    52                         bool sort_ignores_case) const;
     51    bool meta_less_than(const VideoMetadata &lhs, const VideoMetadata &rhs) const;
    5352
    5453    void saveAsDefault();
    5554
    class VideoFilterSettings  
    190189    const QRegExp re_season;
    191190    const QRegExp re_date;
    192191
    193 
    194192    unsigned int m_changed_state;
    195193};
    196194
  • mythtv/programs/mythfrontend/videolist.cpp

    diff --git a/mythtv/programs/mythfrontend/videolist.cpp b/mythtv/programs/mythfrontend/videolist.cpp
    index 7bcbda0..a80b0dc 100644
    a b QString TreeNodeData::GetPrefix(void) const  
    149149/// metadata sort function
    150150struct metadata_sort
    151151{
    152     metadata_sort(const VideoFilterSettings &vfs, bool sort_ignores_case) :
    153         m_vfs(vfs), m_sic(sort_ignores_case) {}
     152    metadata_sort(const VideoFilterSettings &vfs) : m_vfs(vfs) {}
    154153
    155154    bool operator()(const VideoMetadata *lhs, const VideoMetadata *rhs)
    156155    {
    157         return m_vfs.meta_less_than(*lhs, *rhs, m_sic);
     156        return m_vfs.meta_less_than(*lhs, *rhs);
    158157    }
    159158
    160159    bool operator()(const smart_meta_node &lhs, const smart_meta_node &rhs)
    161160    {
    162         return m_vfs.meta_less_than(*(lhs->getData()), *(rhs->getData()),
    163                                     m_sic);
     161        return m_vfs.meta_less_than(*(lhs->getData()), *(rhs->getData()));
    164162    }
    165163
    166164  private:
    167165    const VideoFilterSettings &m_vfs;
    168     bool m_sic;
    169166};
    170167
    171168struct metadata_path_sort
    172169{
    173     explicit metadata_path_sort(bool ignore_case) : m_ignore_case(ignore_case) {}
     170    explicit metadata_path_sort(void) {}
    174171
    175172    bool operator()(const VideoMetadata &lhs, const VideoMetadata &rhs)
    176173    {
    struct metadata_path_sort  
    184181
    185182    bool operator()(const smart_dir_node &lhs, const smart_dir_node &rhs)
    186183    {
    187         return sort(lhs->getPath(), rhs->getPath());
     184        return sort(lhs->getSortPath(), rhs->getSortPath());
    188185    }
    189186
    190187  private:
    191188    bool sort(const VideoMetadata *lhs, const VideoMetadata *rhs)
    192189    {
    193         return sort(lhs->GetFilename(), rhs->GetFilename());
     190        return sort(lhs->GetSortFilename(), rhs->GetSortFilename());
    194191    }
    195192
    196193    bool sort(const QString &lhs, const QString &rhs)
    197194    {
    198         QString lhs_comp(lhs);
    199         QString rhs_comp(rhs);
    200         if (m_ignore_case)
    201         {
    202             lhs_comp = lhs_comp.toLower();
    203             rhs_comp = rhs_comp.toLower();
    204         }
    205         return naturalCompare(lhs_comp, rhs_comp) < 0;
     195        return naturalCompare(lhs, rhs) < 0;
    206196    }
    207 
    208     bool m_ignore_case;
    209197};
    210198
    211199static QString path_to_node_name(const QString &path)
    void VideoListImp::sort_view_data(bool flat_list)  
    751739    if (flat_list)
    752740    {
    753741        sort(m_metadata_view_flat.begin(), m_metadata_view_flat.end(),
    754              metadata_sort(m_video_filter, true));
     742             metadata_sort(m_video_filter));
    755743    }
    756744    else
    757745    {
    758         m_metadata_view_tree.sort(metadata_path_sort(true),
    759                                   metadata_sort(m_video_filter,
    760                                                 true));
     746        m_metadata_view_tree.sort(metadata_path_sort(),
     747                                  metadata_sort(m_video_filter));
    761748    }
    762749}
    763750
    void VideoListImp::buildGroupList(metadata_list_type whence)  
    811798    transform(m_metadata.getList().begin(), m_metadata.getList().end(),
    812799              mli, to_metadata_ptr());
    813800
    814     metadata_path_sort mps(true);
     801    metadata_path_sort mps = metadata_path_sort();
    815802    sort(mlist.begin(), mlist.end(), mps);
    816803
    817804    typedef map<QString, meta_dir_node *> group_to_node_map;
    void VideoListImp::buildTVList(void)  
    944931    transform(m_metadata.getList().begin(), m_metadata.getList().end(),
    945932              mli, to_metadata_ptr());
    946933
    947     metadata_path_sort mps(true);
     934    metadata_path_sort mps = metadata_path_sort();
    948935    sort(mlist.begin(), mlist.end(), mps);
    949936
    950937    meta_dir_node *video_root = &m_metadata_tree;
    void VideoListImp::buildDbList()  
    990977
    991978//    print_meta_list(mlist);
    992979
    993     metadata_path_sort mps(true);
     980    metadata_path_sort mps = metadata_path_sort();
    994981    sort(mlist.begin(), mlist.end(), mps);
    995982
    996983    // TODO: break out the prefix in the DB so this isn't needed
    void VideoListImp::update_meta_view(bool flat_list)  
    11451132
    11461133    m_metadata_view_tree.clear();
    11471134
    1148     // a big punt on setting the sort key
    1149     // TODO: put this in the DB, half the time in this function is spent
    1150     // doing this.
    1151     for (metadata_list::const_iterator si = m_metadata.getList().begin();
    1152          si != m_metadata.getList().end(); ++si)
    1153     {
    1154         if (!(*si)->HasSortKey())
    1155         {
    1156             VideoMetadata::SortKey skey =
    1157                 VideoMetadata::GenerateDefaultSortKey(*(*si), true);
    1158             (*si)->SetSortKey(skey);
    1159         }
    1160     }
    1161 
    11621135    if (flat_list)
    11631136    {
    11641137        for (metadata_list::const_iterator p = m_metadata.getList().begin();
  • mythtv/programs/mythpreviewgen/main.cpp

    diff --git a/mythtv/programs/mythpreviewgen/main.cpp b/mythtv/programs/mythpreviewgen/main.cpp
    index 87ea784..36fface 100644
    a b int preview_helper(uint chanid, QDateTime starttime,  
    106106            return GENERIC_EXIT_NOT_OK;
    107107        }
    108108        pginfo = new ProgramInfo(
    109             infile, ""/*plot*/, ""/*title*/, ""/*subtitle*/, ""/*director*/,
    110             0/*season*/, 0/*episode*/, ""/*inetref*/, 120/*length_in_minutes*/,
    111             1895/*year*/, ""/*id*/);
     109            infile, ""/*plot*/, ""/*title*/, ""/*sortTitle*/, ""/*subtitle*/,
     110            ""/*sortSubtitle*/, ""/*director*/, 0/*season*/, 0/*episode*/,
     111            ""/*inetref*/, 120/*length_in_minutes*/, 1895/*year*/, ""/*id*/);
    112112    }
    113113    else
    114114    {