Ticket #6346: MythVideo.SeasSubEp.4.12.09.diff

File MythVideo.SeasSubEp.4.12.09.diff, 121.9 KB (added by robert.mcnamara@…, 15 years ago)

Add Hunt by Title/Subtitle?

  • mythplugins/mythvideo/theme/default/video-ui.xml

     
    477477        </buttonlist>
    478478
    479479        <textarea name="title" from="basetextarea">
    480             <area>40,20,700,100</area>
     480            <area>40,15,700,100</area>
    481481            <multiline>yes</multiline>
    482482            <font>baseextralarge</font>
    483483        </textarea>
    484484
     485        <textarea name="subtitle" from="basetextarea">
     486            <area>40,45,500,100</area>
     487            <multiline>yes</multiline>
     488            <font>basemedium</font>
     489        </textarea>
     490
     491        <textarea name="##x##" from="basetextarea">
     492            <area>560,45,100,100</area>
     493            <multiline>yes</multiline>
     494            <font>basemedium</font>
     495        </textarea>
     496
    485497        <imagetype name="coverimage">
    486498            <area>30,90,203,311</area>
    487499            <preserveaspect>yes</preserveaspect>
     
    493505        </textarea>
    494506
    495507        <textarea name="dirlbl" from="basetextarea">
    496             <area>240,65,115,35</area>
     508            <area>240,68,115,35</area>
    497509            <value>Directed by</value>
    498510            <align>right</align>
    499511        </textarea>
    500512
    501513        <textarea name="director" from="basetextarea">
    502             <area>360,63,350,35</area>
     514            <area>360,66,350,35</area>
    503515            <font>basemedium</font>
    504516        </textarea>
    505517
     
    586598
    587599    <window name="gallery">
    588600        <textarea name="title" from="basetextarea">
    589             <area>70,20,460,50</area>
     601            <area>70,15,460,50</area>
    590602            <cutdown>yes</cutdown>
    591603            <font>baselarge</font>
    592604        </textarea>
    593605
     606        <textarea name="subtitle" from="basetextarea">
     607            <area>70,40,360,50</area>
     608            <cutdown>yes</cutdown>
     609            <font>basemedium</font>
     610        </textarea>
     611
     612        <textarea name="##x##" from="basetextarea">
     613            <area>440,40,70,50</area>
     614            <cutdown>yes</cutdown>
     615            <font>basemedium</font>
     616        </textarea>
     617
    594618        <buttonlist name="videos">
    595619            <area>15,0,770,585</area>
    596620            <layout>grid</layout>
     
    662686        </buttonlist>
    663687
    664688        <textarea name="position" from="basetextarea">
    665             <area>530,20,110,40</area>
     689            <area>530,15,110,40</area>
    666690            <align>hcenter,vcenter</align>
    667691            <font>basemedium</font>
    668692        </textarea>
     
    728752            <font>baselarge</font>
    729753        </textarea>
    730754
     755        <textarea name="subtitle" from="basetextarea">
     756            <area>50,360,425,30</area>
     757        </textarea>
     758
     759        <textarea name="##x##" from="basetextarea">
     760            <area>500,360,80,30</area>
     761            <align>right</align>
     762        </textarea>
     763
    731764        <textarea name="director" from="basetextarea">
    732             <area>50,367,450,30</area>
     765            <area>50,390,450,30</area>
    733766        </textarea>
    734767
    735768        <textarea name="year" from="basetextarea">
    736             <area>500,367,80,30</area>
     769            <area>500,390,80,30</area>
    737770            <align>right</align>
    738771        </textarea>
    739772
    740773        <textarea name="plot" from="basetextarea">
    741             <area>40,395,530,80</area>
     774            <area>40,418,530,80</area>
    742775            <align>left,top</align>
    743776            <multiline>yes</multiline>
    744777            <cutdown>yes</cutdown>
    745778        </textarea>
    746779
    747780        <textarea name="cast" from="basetextarea">
    748             <area>60,480,505,70</area>
     781            <area>60,503,505,50</area>
    749782            <align>left,top</align>
    750783            <multiline>yes</multiline>
    751784            <cutdown>no</cutdown>
     
    867900        <!-- Labels  -->
    868901
    869902        <textarea name="title_text" from="basetextarea">
    870             <area>50,90,250,40</area>
    871             <value>Name:</value>
     903            <area>50,80,250,40</area>
     904            <value>Title:</value>
    872905            <align>right,top</align>
    873906        </textarea>
    874907
     908        <textarea name="subtitle_text" from="basetextarea">
     909            <area>50,138,250,40</area>
     910            <value>Subtitle:</value>
     911            <align>right,top</align>
     912        </textarea>
     913
     914        <textarea name="season_text" from="basetextarea">
     915            <area>50,185,250,40</area>
     916            <value>Season:</value>
     917            <align>right,top</align>
     918        </textarea>
     919
     920        <textarea name="episode_text" from="basetextarea">
     921            <area>370,185,150,40</area>
     922            <value>Episode:</value>
     923            <align>right,top</align>
     924        </textarea>
     925
    875926        <textarea name="category_text" from="title_text">
    876             <position>50,152</position>
     927            <area>370,232,150,40</area>
     928            <align>right</align>
    877929            <value>Category:</value>
    878930        </textarea>
    879931
    880932        <textarea name="level_text" from="title_text">
    881             <position>50,202</position>
     933            <area>20,232,200,40</area>
     934            <align>right</align>
    882935            <value>Parental Control:</value>
    883936        </textarea>
    884937
    885938        <textarea name="child_text" from="title_text">
    886             <position>50,247</position>
     939            <area>20,277,200,40</area>
     940            <align>right</align>
    887941            <value>File to Always Play Next:</value>
    888942        </textarea>
    889943
    890944        <textarea name="browse_text" from="title_text">
    891             <position>50,292</position>
     945            <area>500,277,200,40</area>
     946            <align>left</align>
    892947            <value>Include while Browsing:</value>
    893948        </textarea>
    894949
     
    925980        <!-- Widgets -->
    926981
    927982        <textedit name="title_edit" from="basetextedit">
    928             <position>310,80</position>
     983            <position>310,70</position>
    929984        </textedit>
    930985
    931         <buttonlist name="category_select" from="baseselector">
    932             <position>310,145</position>
    933         </buttonlist>
     986        <textedit name="subtitle_edit" from="basetextedit">
     987            <position>310,126</position>
     988        </textedit>
    934989
     990        <spinbox name="season" from="basespinbox">
     991            <position>310,181</position>
     992        </spinbox>
     993
     994        <spinbox name="episode" from="basespinbox">
     995            <position>530,181</position>
     996        </spinbox>
     997
    935998        <buttonlist name="level_select" from="baseselector">
    936             <position>310,195</position>
     999            <position>230,225</position>
    9371000        </buttonlist>
    9381001
     1002        <buttonlist name="category_select" from="baseselector">
     1003            <position>530,225</position>
     1004        </buttonlist>
     1005
    9391006        <buttonlist name="child_select" from="baseselector">
    940             <position>310,240</position>
     1007            <position>230,270</position>
    9411008        </buttonlist>
    9421009
    9431010        <checkbox name="browse_check" from="basecheckbox">
    944             <position>310,290</position>
     1011            <position>680,275</position>
    9451012        </checkbox>
    9461013
    9471014        <button name="coverart_button" from="basesearchbutton">
  • mythplugins/mythvideo/theme/default-wide/video-ui.xml

     
    467467        </imagetype>
    468468
    469469        <textarea name="title" from="basetextarea">
    470             <area>370,12,700,40</area>
     470            <area>370,12,400,40</area>
    471471            <multiline>yes</multiline>
    472472            <font>baselarge</font>
    473473        </textarea>
    474474
     475        <textarea name="subtitle" from="basetextarea">
     476            <area>800,12,400,40</area>
     477            <multiline>yes</multiline>
     478            <font>baselarge</font>
     479        </textarea>
     480
    475481        <textarea name="currentvideo" from="basetextarea">
    476482            <area>150,486,500,35</area>
    477483            <align>top,vcenter</align>
     
    487493            <font>basemedium</font>
    488494        </textarea>
    489495
     496        <textarea name="s##e##" from="basetextarea">
     497            <area>1010,63,150,35</area>
     498            <font>basemedium</font>
     499        </textarea>
     500
    490501        <textarea name="plot" from="basetextarea">
    491502            <area>380,97,840,145</area>
    492503            <multiline>yes</multiline>
     
    572583
    573584    <window name="gallery">
    574585        <textarea name="title" from="basetextarea">
    575             <area>70,15,800,50</area>
     586            <area>70,15,420,50</area>
    576587            <cutdown>yes</cutdown>
    577588            <font>baselarge</font>
    578589        </textarea>
     
    646657                </state>
    647658            </statetype>
    648659        </buttonlist>
     660       
     661        <textarea name="subtitle" from="basetextarea">
     662            <area>500,15,350,40</area>
     663            <align>hcenter,vcenter</align>
     664            <font>basemedium</font>
     665        </textarea>
    649666
     667        <textarea name="s##e##" from="basetextarea">
     668            <area>870,15,100,40</area>
     669            <align>hcenter,vcenter</align>
     670            <font>basemedium</font>
     671        </textarea>       
     672
    650673        <textarea name="position" from="basetextarea">
    651             <area>890,15,200,40</area>
     674            <area>1000,15,200,40</area>
    652675            <align>hcenter,vcenter</align>
    653676            <font>basemedium</font>
    654677        </textarea>
     
    713736            <font>baselarge</font>
    714737        </textarea>
    715738
     739        <textarea name="s##e##" from="basetextarea">
     740            <area>50,380,400,30</area>
     741            <font>basemedium</font>
     742        </textarea>
     743
     744        <textarea name="subtitle" from="basetextarea">
     745            <area>50,420,400,30</area>
     746            <font>basemedium</font>
     747        </textarea>
     748
    716749        <textarea name="director" from="basetextarea">
    717             <area>50,367,450,30</area>
     750            <area>50,467,450,30</area>
    718751        </textarea>
    719752
    720753        <textarea name="year" from="basetextarea">
    721             <area>500,367,80,30</area>
     754            <area>500,467,80,30</area>
    722755            <align>right</align>
    723756        </textarea>
    724757
    725758        <textarea name="plot" from="basetextarea">
    726             <area>40,395,530,80</area>
     759            <area>40,495,530,80</area>
    727760            <align>left,top</align>
    728761            <multiline>yes</multiline>
    729762            <cutdown>yes</cutdown>
    730763        </textarea>
    731764
    732765        <textarea name="cast" from="basetextarea">
    733             <area>60,480,505,70</area>
     766            <area>60,580,505,70</area>
    734767            <align>left,top</align>
    735768            <multiline>yes</multiline>
    736769            <cutdown>no</cutdown>
    737770        </textarea>
    738771
    739772        <textarea name="position" from="basetextarea">
    740             <area>266,555,266,40</area>
     773            <area>266,655,266,40</area>
    741774            <font>basemedium</font>
    742775            <align>hcenter,vcenter</align>
    743776        </textarea>
     
    843876    <window name="edit_metadata">
    844877
    845878        <textarea name="title" from="basetextarea">
    846             <area>10,50,1260,50</area>
     879            <area>10,30,760,50</area>
    847880            <value>Edit Video Information</value>
    848881            <align>hcenter,vcenter</align>
    849882            <font>baselarge</font>
     
    852885        <!-- Labels  -->
    853886
    854887        <textarea name="title_text" from="basetextarea">
    855             <area>250,110,250,40</area>
    856             <value>Name:</value>
     888            <area>50,80,250,40</area>
     889            <value>Title:</value>
    857890            <align>right,top</align>
    858891        </textarea>
    859892
     893        <textarea name="subtitle_text" from="basetextarea">
     894            <area>50,138,250,40</area>
     895            <value>Subtitle:</value>
     896            <align>right,top</align>
     897        </textarea>
     898
     899        <textarea name="season_text" from="basetextarea">
     900            <area>50,185,250,40</area>
     901            <value>Season:</value>
     902            <align>right,top</align>
     903        </textarea>
     904
     905        <textarea name="episode_text" from="basetextarea">
     906            <area>370,185,150,40</area>
     907            <value>Episode:</value>
     908            <align>right,top</align>
     909        </textarea>
     910
    860911        <textarea name="category_text" from="title_text">
    861             <position>250,172</position>
     912            <area>420,232,150,40</area>
     913            <align>right</align>
    862914            <value>Category:</value>
    863915        </textarea>
    864916
    865917        <textarea name="level_text" from="title_text">
    866             <position>250,222</position>
     918            <area>20,232,200,40</area>
     919            <align>right</align>
    867920            <value>Parental Control:</value>
    868921        </textarea>
    869922
    870923        <textarea name="child_text" from="title_text">
    871             <position>250,267</position>
     924            <area>20,277,200,40</area>
     925            <align>right</align>
    872926            <value>File to Always Play Next:</value>
    873927        </textarea>
    874928
    875929        <textarea name="browse_text" from="title_text">
    876             <position>250,312</position>
     930            <area>470,277,280,40</area>
     931            <align>left</align>
    877932            <value>Include while Browsing:</value>
    878933        </textarea>
    879934
    880935        <textarea name="coverart_text_label" from="title_text">
    881             <position>250,348</position>
     936            <position>50,328</position>
    882937            <value>Cover Art:</value>
    883938        </textarea>
    884939
    885940        <textarea name="screenshot_text_label" from="title_text">
    886             <position>250,377</position>
     941            <position>50,357</position>
    887942            <value>Screenshot:</value>
    888943        </textarea>
    889944
    890945        <textarea name="banner_text_label" from="title_text">
    891             <position>250,406</position>
     946            <position>50,386</position>
    892947            <value>Banner:</value>
    893948        </textarea>
    894949
    895950        <textarea name="fanart_text_label" from="title_text">
    896             <position>250,435</position>
     951            <position>50,415</position>
    897952            <value>Fanart:</value>
    898953        </textarea>
    899954
    900955        <textarea name="trailer_text_label" from="title_text">
    901             <position>250,464</position>
     956            <position>50,447</position>
    902957            <value>Trailer:</value>
    903958        </textarea>
    904959
    905960        <textarea name="player_text" from="title_text">
    906             <position>250,510</position>
     961            <position>50,487</position>
    907962            <value>Unique Player Command:</value>
    908963        </textarea>
    909964
    910965        <!-- Widgets -->
    911966
    912967        <textedit name="title_edit" from="basetextedit">
    913             <position>510,100</position>
     968            <position>310,70</position>
    914969        </textedit>
    915970
    916         <buttonlist name="category_select" from="baseselector">
    917             <position>510,165</position>
    918         </buttonlist>
     971        <textedit name="subtitle_edit" from="basetextedit">
     972            <position>310,126</position>
     973        </textedit>
    919974
     975        <spinbox name="season" from="basespinbox">
     976            <position>310,181</position>
     977        </spinbox>
     978
     979        <spinbox name="episode" from="basespinbox">
     980            <position>530,181</position>
     981        </spinbox>
     982
    920983        <buttonlist name="level_select" from="baseselector">
    921             <position>510,215</position>
     984            <position>230,225</position>
    922985        </buttonlist>
    923986
     987        <buttonlist name="category_select" from="baseselector">
     988            <position>580,225</position>
     989        </buttonlist>
     990
    924991        <buttonlist name="child_select" from="baseselector">
    925             <position>510,260</position>
     992            <position>230,270</position>
    926993        </buttonlist>
    927994
    928995        <checkbox name="browse_check" from="basecheckbox">
    929             <position>510,310</position>
     996            <position>735,275</position>
    930997        </checkbox>
    931998
    932         <button name="coverart_button" from="basesearchbutton">
    933             <position>510,343</position>
     999        <button name="coverart_button">
     1000            <area>310,323,32,32</area>
     1001            <statetype name="buttonstate">
     1002                <state name="active">
     1003                    <imagetype name="background">
     1004                        <filename>blankbutton_off.png</filename>
     1005                    </imagetype>
     1006                </state>
     1007                <state name="selected" from="active">
     1008                    <imagetype name="background">
     1009                        <filename>blankbutton_on.png</filename>
     1010                    </imagetype>
     1011                </state>
     1012                <state name="disabled" from="active" />
     1013                <state name="pushed" from="active">
     1014                    <imagetype name="background">
     1015                        <filename>blankbutton_pushed.png</filename>
     1016                    </imagetype>
     1017                </state>
     1018            </statetype>
    9341019        </button>
    9351020
    9361021        <textarea name="coverart_text" from="basetextarea">
    937             <area>550,348,250,40</area>
     1022            <area>350,328,250,40</area>
    9381023            <value>/path/to/the/thing.jpg</value>
    9391024        </textarea>
    9401025
    941         <button name="screenshot_button" from="basesearchbutton">
    942             <position>510,372</position>
     1026        <button name="screenshot_button">
     1027            <area>310,352,32,32</area>
     1028            <statetype name="buttonstate">
     1029                <state name="active">
     1030                    <imagetype name="background">
     1031                        <filename>blankbutton_off.png</filename>
     1032                    </imagetype>
     1033                </state>
     1034                <state name="selected" from="active">
     1035                    <imagetype name="background">
     1036                        <filename>blankbutton_on.png</filename>
     1037                    </imagetype>
     1038                </state>
     1039                <state name="disabled" from="active" />
     1040                <state name="pushed" from="active">
     1041                    <imagetype name="background">
     1042                        <filename>blankbutton_pushed.png</filename>
     1043                    </imagetype>
     1044                </state>
     1045            </statetype>
    9431046        </button>
    9441047
    9451048        <textarea name="screenshot_text" from="basetextarea">
    946             <area>550,377,250,40</area>
     1049            <area>350,357,250,40</area>
    9471050            <value>/path/to/the/thing.jpg</value>
    9481051        </textarea>
    9491052
    950         <button name="banner_button" from="basesearchbutton">
    951             <position>510,401</position>
     1053        <button name="banner_button">
     1054            <area>310,381,32,32</area>
     1055            <statetype name="buttonstate">
     1056                <state name="active">
     1057                    <imagetype name="background">
     1058                        <filename>blankbutton_off.png</filename>
     1059                    </imagetype>
     1060                </state>
     1061                <state name="selected" from="active">
     1062                    <imagetype name="background">
     1063                        <filename>blankbutton_on.png</filename>
     1064                    </imagetype>
     1065                </state>
     1066                <state name="disabled" from="active" />
     1067                <state name="pushed" from="active">
     1068                    <imagetype name="background">
     1069                        <filename>blankbutton_pushed.png</filename>
     1070                    </imagetype>
     1071                </state>
     1072            </statetype>
    9521073        </button>
    9531074
    9541075        <textarea name="banner_text" from="basetextarea">
    955             <area>550,406,250,40</area>
     1076            <area>350,386,250,40</area>
    9561077            <value>/path/to/the/thing.jpg</value>
    9571078        </textarea>
    9581079
    959         <button name="fanart_button" from="basesearchbutton">
    960             <position>510,430</position>
     1080        <button name="fanart_button">
     1081            <area>310,412,32,32</area>
     1082            <statetype name="buttonstate">
     1083                <state name="active">
     1084                    <imagetype name="background">
     1085                        <filename>blankbutton_off.png</filename>
     1086                    </imagetype>
     1087                </state>
     1088                <state name="selected" from="active">
     1089                    <imagetype name="background">
     1090                        <filename>blankbutton_on.png</filename>
     1091                    </imagetype>
     1092                </state>
     1093                <state name="disabled" from="active" />
     1094                <state name="pushed" from="active">
     1095                    <imagetype name="background">
     1096                        <filename>blankbutton_pushed.png</filename>
     1097                    </imagetype>
     1098                </state>
     1099            </statetype>
    9611100        </button>
    9621101
    9631102        <textarea name="fanart_text" from="basetextarea">
    964             <area>550,435,250,40</area>
     1103            <area>350,415,250,40</area>
    9651104            <value>/path/to/the/thing.jpg</value>
    9661105        </textarea>
    9671106
    968         <button name="trailer_button" from="basesearchbutton">
    969             <position>510,460</position>
     1107        <button name="trailer_button">
     1108            <area>310,442,32,32</area>
     1109            <statetype name="buttonstate">
     1110                <state name="active">
     1111                    <imagetype name="background">
     1112                        <filename>blankbutton_off.png</filename>
     1113                    </imagetype>
     1114                </state>
     1115                <state name="selected" from="active">
     1116                    <imagetype name="background">
     1117                        <filename>blankbutton_on.png</filename>
     1118                    </imagetype>
     1119                </state>
     1120                <state name="disabled" from="active" />
     1121                <state name="pushed" from="active">
     1122                    <imagetype name="background">
     1123                        <filename>blankbutton_pushed.png</filename>
     1124                    </imagetype>
     1125                </state>
     1126            </statetype>
    9701127        </button>
    9711128
    9721129        <textarea name="trailer_text" from="basetextarea">
    973             <area>550,465,250,40</area>
     1130            <area>350,447,250,40</area>
    9741131            <value>/path/to/the/thing.jpg</value>
    9751132        </textarea>
    9761133
     1134
    9771135        <textedit name="player_edit" from="basetextedit">
    978             <position>510,495</position>
     1136            <position>310,477</position>
    9791137        </textedit>
    9801138
    9811139        <button name="done_button" from="basebutton">
    982             <position>510,565</position>
     1140            <position>310,537</position>
    9831141            <value>Done</value>
    9841142        </button>
    9851143
  • mythplugins/mythvideo/mythvideo/videodlg.h

     
    2828
    2929enum CoverDownloadErrorState { esOK, esError, esTimeout };
    3030enum FanartDownloadErrorState { fesOK, fesError, fesTimeout };
     31enum BannerDownloadErrorState { besOK, besError, besTimeout };
    3132
    3233class VideoDialog : public MythScreenType
    3334{
     
    6869
    6970    void EditMetadata();
    7071    void VideoSearch();
     72    void TitleSubtitleSearch();
     73    void ImageOnlyDownload();
    7174    void ManualVideoUID();
    7275    void ManualVideoTitle();
    7376    void ResetMetadata();
     
    140143    // OnVideoPosterSetDone() stop wait background
    141144    void StartVideoPosterSet(Metadata *metadata);
    142145    void StartVideoFanartSet(Metadata *metadata);
     146    void StartVideoBannerSet(Metadata *metadata);
    143147
    144148    // StartVideoSearchByUID() start wait background
    145149    //   OnVideoSearchByUIDDone() stop wait background
     
    150154    //   OnVideoSearchByTitleDone()
    151155    void StartVideoSearchByTitle(QString video_uid, QString title,
    152156            Metadata *metadata);
     157    void StartVideoSearchByTitleSubtitle(QString title,
     158            QString subtitle, Metadata *metadata);
    153159
    154160  private slots:
    155161    // called during StartVideoPosterSet
     
    159165    void OnFanartURL(QString uri, Metadata *metadata);
    160166    void OnFanartCopyFinished(FanartDownloadErrorState error, QString errorMsg,
    161167                              Metadata *metadata);
     168    void OnBannerURL(QString uri, Metadata *metadata);
     169    void OnBannerCopyFinished(BannerDownloadErrorState error, QString errorMsg,
     170                              Metadata *metadata);
    162171
    163172    // called during StartVideoSearchByTitle
    164173    void OnVideoSearchByTitleDone(bool normal_exit,
    165174                                  const SearchListResults &results,
    166175                                  Metadata *metadata);
     176    void OnVideoSearchByTitleSubtitleDone(bool normal_exit,
     177                                  QStringList result,
     178                                  Metadata *metadata);
    167179
    168180// and now the end points
    169181
    170182    // StartVideoPosterSet end
    171183    void OnVideoPosterSetDone(Metadata *metadata);
    172184    void OnVideoFanartSetDone(Metadata *metadata);
     185    void OnVideoBannerSetDone(Metadata *metadata);
    173186
    174187    // StartVideoSearchByUID end
    175188    void OnVideoSearchByUIDDone(bool normal_exit,
  • mythplugins/mythvideo/mythvideo/metadatalistmanager.cpp

     
    112112    MSqlQuery query(MSqlQuery::InitCon());
    113113    query.setForwardOnly(true);
    114114    const QString BaseMetadataQuery(
    115         "SELECT title, director, plot, rating, year, userrating,"
    116         "length, filename, showlevel, coverfile, inetref, childid,"
    117         "browse, playcommand, category, intid, trailer, screenshot,"
    118         "banner, fanart, host FROM videometadata");
     115        "SELECT title, director, plot, rating, year, "
     116        "userrating, length, filename, showlevel, "
     117        "coverfile, inetref, childid, browse, playcommand, category, "
     118        "intid, trailer, screenshot, banner, fanart, "
     119        "subtitle, season, episode, host FROM videometadata");
    119120
    120121    query.prepare(BaseMetadataQuery);
    121122
  • mythplugins/mythvideo/mythvideo/metadata.cpp

     
    8989  public:
    9090    MetadataImp(const QString &filename, const QString &trailer, const QString &coverfile,
    9191             const QString &screenshot, const QString &banner, const QString &fanart,
    92              const QString &title, int year,
     92             const QString &title, const QString &subtitle, int year,
    9393             const QString &inetref, const QString &director,
    9494             const QString &plot, float userrating,
    9595             const QString &rating, int length,
     96             int season, int episode,
    9697             int id, ParentalLevel::Level showlevel, int categoryID,
    9798             int childID, bool browse,
    9899             const QString &playcommand, const QString &category,
     
    100101             const country_list &countries,
    101102             const cast_list &cast,
    102103             const QString &host = "") :
    103         m_title(title),
     104        m_title(title), m_subtitle(subtitle),
    104105        m_inetref(inetref), m_director(director), m_plot(plot),
    105106        m_rating(rating), m_playcommand(playcommand), m_category(category),
    106107        m_genres(genres), m_countries(countries), m_cast(cast),
    107108        m_filename(filename), m_trailer(trailer), m_coverfile(coverfile),
    108109        m_screenshot(screenshot), m_banner(banner), m_fanart(fanart),
    109110        m_host(host), m_categoryID(categoryID), m_childID(childID),
    110         m_year(year), m_length(length), m_showlevel(showlevel),
     111        m_year(year), m_length(length), m_season(season),
     112        m_episode(episode), m_showlevel(showlevel),
    111113        m_browse(browse), m_id(id), m_userrating(userrating)
    112114    {
    113115        VideoCategory::GetCategory().get(m_categoryID, m_category);
     
    128130        if (this != &rhs)
    129131        {
    130132            m_title = rhs.m_title;
     133            m_subtitle = rhs.m_subtitle;
    131134            m_inetref = rhs.m_inetref;
    132135            m_director = rhs.m_director;
    133136            m_plot = rhs.m_plot;
     
    148151            m_childID = rhs.m_childID;
    149152            m_year = rhs.m_year;
    150153            m_length = rhs.m_length;
     154            m_season = rhs.m_season;
     155            m_episode = rhs.m_episode;
    151156            m_showlevel = rhs.m_showlevel;
    152157            m_browse = rhs.m_browse;
    153158            m_id = rhs.m_id;
     
    180185        m_title = title;
    181186    }
    182187
     188    const QString &getSubtitle() const { return m_subtitle; }
     189    void SetSubtitle(const QString &subtitle) { m_subtitle = subtitle; }
     190
    183191    const QString &GetInetRef() const { return m_inetref; }
    184192    void SetInetRef(const QString &inetRef) { m_inetref = inetRef; }
    185193
     
    249257    int GetLength() const { return m_length; }
    250258    void SetLength(int length) { m_length = length; }
    251259
     260    int GetSeason() const { return m_season; }
     261    void SetSeason(int season) { m_season = season; }
     262
     263    int GetEpisode() const { return m_episode; }
     264    void SetEpisode(int episode) { m_episode = episode; }
     265
    252266    ParentalLevel::Level GetShowLevel() const { return m_showlevel; }
    253267    void SetShowLevel(ParentalLevel::Level showLevel)
    254268    {
     
    289303
    290304  private:
    291305    QString m_title;
     306    QString m_subtitle;
    292307    QString m_inetref;
    293308    QString m_director;
    294309    QString m_plot;
     
    310325    int m_childID;
    311326    int m_year;
    312327    int m_length;
     328    int m_season;
     329    int m_episode;
    313330    ParentalLevel::Level m_showlevel;
    314331    bool m_browse;
    315332    unsigned int m_id;  // videometadata.intid
     
    383400{
    384401    MetadataImp tmp(m_filename, VIDEO_TRAILER_DEFAULT, VIDEO_COVERFILE_DEFAULT,
    385402                    VIDEO_SCREENSHOT_DEFAULT, VIDEO_BANNER_DEFAULT,
    386                     VIDEO_FANART_DEFAULT, Metadata::FilenameToTitle(m_filename),
    387                     VIDEO_YEAR_DEFAULT, VIDEO_INETREF_DEFAULT,
    388                     VIDEO_DIRECTOR_DEFAULT, VIDEO_PLOT_DEFAULT, 0.0,
    389                     VIDEO_RATING_DEFAULT, 0, m_id,
     403                    VIDEO_FANART_DEFAULT, Metadata::FilenameToMeta(m_filename, 1),
     404                    Metadata::FilenameToMeta(m_filename, 4), VIDEO_YEAR_DEFAULT,
     405                    VIDEO_INETREF_DEFAULT, VIDEO_DIRECTOR_DEFAULT,
     406                    VIDEO_PLOT_DEFAULT, 0.0,
     407                    VIDEO_RATING_DEFAULT, 0,
     408                    Metadata::FilenameToMeta(m_filename, 2).toInt(),
     409                    Metadata::FilenameToMeta(m_filename, 3).toInt(), m_id,
    390410                    ParentalLevel::plLowest, 0, -1, true, "", "",
    391411                    Metadata::genre_list(), Metadata::country_list(),
    392412                    Metadata::cast_list(), m_host);
     
    484504    m_screenshot = query.value(17).toString();
    485505    m_banner = query.value(18).toString();
    486506    m_fanart = query.value(19).toString();
    487     m_host = query.value(20).toString();
     507    m_subtitle = query.value(20).toString();
     508    m_season = query.value(21).toInt();
     509    m_episode = query.value(22).toInt();
     510    m_host = query.value(23).toString();
    488511
    489512    VideoCategory::GetCategory().get(m_categoryID, m_category);
    490513
     
    501524void MetadataImp::saveToDatabase()
    502525{
    503526    if (m_title.isEmpty())
    504         m_title = Metadata::FilenameToTitle(m_filename);
     527        m_title = Metadata::FilenameToMeta(m_filename, 1);
     528    if (m_subtitle.isEmpty())
     529        m_subtitle = Metadata::FilenameToMeta(m_filename, 4);
    505530    if (m_director.isEmpty())
    506531        m_director = VIDEO_DIRECTOR_UNKNOWN;
    507532    if (m_plot.isEmpty())
    508533        m_plot = VIDEO_PLOT_DEFAULT;
    509534    if (m_rating.isEmpty())
    510535        m_rating = VIDEO_RATING_DEFAULT;
     536    if (m_season == 0)
     537        m_season = Metadata::FilenameToMeta(m_filename, 2).toInt();
     538    if (m_episode == 0)
     539        m_episode = Metadata::FilenameToMeta(m_filename, 3).toInt();
    511540    if (m_coverfile.isEmpty())
    512541        m_coverfile = VIDEO_COVERFILE_DEFAULT;
    513542    if (m_screenshot.isEmpty())
     
    533562    {
    534563        m_browse = gContext->GetNumSetting("VideoNewBrowsable", 1);
    535564
    536         query.prepare("INSERT INTO videometadata (title,director,plot,"
    537                       "rating,year,userrating,length,filename,showlevel,"
    538                       "coverfile,inetref,browse,trailer,screenshot,banner,"
    539                       "fanart,host) VALUES (:TITLE, :DIRECTOR, :PLOT, :RATING, "
    540                       ":YEAR, :USERRATING, :LENGTH, :FILENAME, :SHOWLEVEL, "
    541                       ":COVERFILE, :INETREF, :BROWSE, :TRAILER, :SCREENSHOT, "
    542                       ":BANNER, :FANART, :HOST)");
     565        query.prepare("INSERT INTO videometadata (title,subtitle,director,plot,"
     566                      "rating,year,userrating,length,season,episode,filename,"
     567                      "showlevel,coverfile,inetref,browse,trailer,screenshot,banner,"
     568                      "fanart,host) VALUES (:TITLE, :SUBTITLE, :DIRECTOR, :PLOT, "
     569                      ":RATING, :YEAR, :USERRATING, :LENGTH, :SEASON, :EPISODE, "
     570                      ":FILENAME, :SHOWLEVEL, :COVERFILE, :INETREF, :BROWSE, "
     571                      ":TRAILER, :SCREENSHOT, :BANNER, :FANART, :HOST)");
    543572    }
    544573    else
    545574    {
    546         query.prepare("UPDATE videometadata SET title = :TITLE, "
     575        query.prepare("UPDATE videometadata SET title = :TITLE, subtitle = :SUBTITLE, "
    547576                      "director = :DIRECTOR, plot = :PLOT, rating= :RATING, "
    548577                      "year = :YEAR, userrating = :USERRATING, "
    549                       "length = :LENGTH, filename = :FILENAME, trailer = :TRAILER, "
     578                      "length = :LENGTH, season = :SEASON, episode = :EPISODE, "
     579                      "filename = :FILENAME, trailer = :TRAILER, "
    550580                      "showlevel = :SHOWLEVEL, coverfile = :COVERFILE, "
    551581                      "screenshot = :SCREENSHOT, banner = :BANNER, fanart = :FANART, "
    552582                      "inetref = :INETREF, browse = :BROWSE, host = :HOST, "
     
    560590    }
    561591
    562592    query.bindValue(":TITLE", m_title);
     593    query.bindValue(":SUBTITLE", m_subtitle);
    563594    query.bindValue(":DIRECTOR", m_director);
    564595    query.bindValue(":PLOT", m_plot);
    565596    query.bindValue(":RATING", m_rating);
    566597    query.bindValue(":YEAR", m_year);
    567598    query.bindValue(":USERRATING", m_userrating);
    568599    query.bindValue(":LENGTH", m_length);
     600    query.bindValue(":SEASON", m_season);
     601    query.bindValue(":EPISODE", m_episode);
    569602    query.bindValue(":FILENAME", m_filename);
    570603    query.bindValue(":TRAILER", m_trailer);
    571604    query.bindValue(":SHOWLEVEL", m_showlevel);
     
    795828    }
    796829}
    797830
    798 QString Metadata::FilenameToTitle(const QString &file_name)
     831QString Metadata::FilenameToMeta(const QString &file_name, int position)
    799832{
     833    // position 1 returns title, 2 returns season,
     834    //          3 returns episode, 4 returns subtitle
     835 
    800836    QString title = file_name.right(file_name.length() -
    801837                                    file_name.lastIndexOf('/') - 1);
     838
    802839    title.replace(QRegExp("_"), " ");
    803840    title.replace(QRegExp("%20"), " ");
     841    title.replace(QRegExp("-"), " ");
    804842    title = title.left(title.lastIndexOf('.'));
    805843    title.replace(QRegExp("\\."), " ");
    806844
    807     title = eatBraces(title, "[", "]");
    808     title = eatBraces(title, "(", ")");
    809     title = eatBraces(title, "{", "}");
     845    QRegExp group("^(.*[^s0-9])" // title
     846                  "(?:[s])?(\\d{1,3})(?:\\s|-)?(?:[ex])" //Season
     847                  "(?:\\s|-)?(\\d{1,3})" // Episode
     848                  "(.*)$", // subtitle
     849                  Qt::CaseInsensitive);
     850    int pos = group.indexIn(title);
     851    if (pos > -1)
     852    {
     853        QString groupResult = group.cap(0);
     854        QString title = group.cap(1);
     855        QString season = group.cap(2);
     856        QString episode = group.cap(3);
     857        QString subtitle = group.cap(4);
     858        if (position == 1 && !title.isEmpty())
     859            return title.trimmed();
     860        else if (position == 2)
     861            return season.trimmed();
     862        else if (position == 3)
     863            return episode.trimmed();
     864        else if (position == 4)
     865            return subtitle.trimmed();
     866    }
     867    else if (position == 1)
     868        {
     869        title = eatBraces(title, "[", "]");
     870        title = eatBraces(title, "(", ")");
     871        title = eatBraces(title, "{", "}");
     872        return title.trimmed();
     873        }
     874    else if (position == 2 || position == 3)
     875        return QString("0");
    810876
    811     return title.trimmed();
     877    return QString("");
    812878}
    813879
    814880namespace
     
    829895    return ret;
    830896}
    831897
    832 Metadata::Metadata(const QString &filename, const QString &trailer,
    833              const QString &coverfile, const QString &screenshot,
    834              const QString &banner, const QString &fanart,
    835              const QString &title, int year,
     898Metadata::Metadata(const QString &filename, const QString &trailer, 
     899             const QString &coverfile, const QString &screenshot, 
     900             const QString &banner, const QString &fanart, 
     901             const QString &title, const QString &subtitle, int year,
    836902             const QString &inetref, const QString &director,
    837903             const QString &plot, float userrating,
    838904             const QString &rating, int length,
     905             int season, int episode,
    839906             int id, ParentalLevel::Level showlevel, int categoryID,
    840907             int childID, bool browse,
    841908             const QString &playcommand, const QString &category,
     
    845912             const QString &host)
    846913{
    847914    m_imp = new MetadataImp(filename, trailer, coverfile, screenshot, banner,
    848                             fanart, title, year, inetref, director, plot,
    849                             userrating, rating, length, id, showlevel,
    850                             categoryID, childID, browse, playcommand, category,
    851                             genres, countries, cast, host);
     915                            fanart, title, subtitle, year, inetref, director, plot,
     916                            userrating, rating, length, season, episode, id,
     917                            showlevel, categoryID, childID, browse, playcommand,
     918                            category, genres, countries, cast, host);
    852919}
    853920
    854921Metadata::~Metadata()
     
    911978    m_imp->SetTitle(title);
    912979}
    913980
     981const QString &Metadata::GetSubtitle() const
     982{
     983    return m_imp->getSubtitle();
     984}
     985 
     986void Metadata::SetSubtitle(const QString &subtitle)
     987{
     988    m_imp->SetSubtitle(subtitle);
     989}
     990
    914991int Metadata::GetYear() const
    915992{
    916993    return m_imp->getYear();
     
    9811058    m_imp->SetLength(length);
    9821059}
    9831060
     1061int Metadata::GetSeason() const
     1062{
     1063    return m_imp->GetSeason();
     1064}
     1065
     1066void Metadata::SetSeason(int season)
     1067{
     1068    m_imp->SetSeason(season);
     1069}
     1070
     1071int Metadata::GetEpisode() const
     1072{
     1073    return m_imp->GetEpisode();
     1074}
     1075
     1076void Metadata::SetEpisode(int episode)
     1077{
     1078    m_imp->SetEpisode(episode);
     1079}
     1080
    9841081unsigned int Metadata::GetID() const
    9851082{
    9861083    return m_imp->GetID();
  • mythplugins/mythvideo/mythvideo/globalsettings.cpp

     
    235235    return gc;
    236236}
    237237
     238HostLineEdit *SearchTVListingsCommand()
     239{
     240    HostLineEdit *gc = new HostLineEdit("mythvideo.TVListCommandLine");
     241    gc->setLabel(QObject::tr("Command to search for TV shows in MythVideo"));
     242    gc->setValue(GetShareDir() + "mythvideo/scripts/ttvdb.py -M");
     243    gc->setHelpText(QObject::tr("This command must be "
     244                    "executable by the user running MythVideo."));
     245    return gc;
     246}
     247
     248HostLineEdit *GetTVPostersCommand()
     249{
     250    HostLineEdit *gc = new HostLineEdit("mythvideo.TVPosterCommandLine");
     251    gc->setLabel(QObject::tr("Command to search for TV Season posters"));
     252    gc->setValue(GetShareDir() + "mythvideo/scripts/ttvdb.py -mP");
     253    gc->setHelpText(QObject::tr("This command must be "
     254                    "executable by the user running MythVideo."));
     255    return gc;
     256}
     257
     258HostLineEdit *GetTVFanartCommand()
     259{
     260    HostLineEdit *gc = new HostLineEdit("mythvideo.TVFanartCommandLine");
     261    gc->setLabel(QObject::tr("Command to search for TV fanart"));
     262    gc->setValue(GetShareDir() + "mythvideo/scripts/ttvdb.py -tF");
     263    gc->setHelpText(QObject::tr("This command must be "
     264                    "executable by the user running MythVideo."));
     265    return gc;
     266}
     267
     268HostLineEdit *GetTVBannerCommand()
     269{
     270    HostLineEdit *gc = new HostLineEdit("mythvideo.TVBannerCommandLine");
     271    gc->setLabel(QObject::tr("Command to search for TV banners"));
     272    gc->setValue(GetShareDir() + "mythvideo/scripts/ttvdb.py -tB");
     273    gc->setHelpText(QObject::tr("This command must be "
     274                    "executable by the user running MythVideo."));
     275    return gc;
     276}
     277
     278HostLineEdit *GetTVDataCommand()
     279{
     280    HostLineEdit *gc = new HostLineEdit("mythvideo.TVDataCommandLine");
     281    gc->setLabel(QObject::tr("Command to extract data for TV Episodes"));
     282    gc->setValue(GetShareDir() + "mythvideo/scripts/ttvdb.py -D");
     283    gc->setHelpText(QObject::tr("This command must be "
     284                    "executable by the user running MythVideo."));
     285    return gc;
     286}
     287
     288HostLineEdit *GetTVTitleSubCommand()
     289{
     290    HostLineEdit *gc = new HostLineEdit("mythvideo.TVTitleSubCommandLine");
     291    gc->setLabel(QObject::tr("Command to search for TV by Title/Subtitle"));
     292    gc->setValue(GetShareDir() + "mythvideo/scripts/ttvdb.py -N");
     293    gc->setHelpText(QObject::tr("This command must be "
     294                    "executable by the user running MythVideo."));
     295    return gc;
     296}
     297
    238298HostLineEdit *VideoStartupDirectory()
    239299{
    240300    HostLineEdit *gc = new HostLineEdit("VideoStartupDir");
     
    776836    VConfigPage page7(pages, false);
    777837    page7->addChild(trlr);
    778838
     839    // page 8
     840    VerticalConfigurationGroup *tvman =
     841            new VerticalConfigurationGroup(true, false);
     842    tvman->setLabel(QObject::tr("Television in MythVideo"));
     843    tvman->addChild(SearchTVListingsCommand());
     844    tvman->addChild(GetTVPostersCommand());
     845    tvman->addChild(GetTVFanartCommand());
     846    tvman->addChild(GetTVBannerCommand());
     847    tvman->addChild(GetTVDataCommand());
     848    tvman->addChild(GetTVTitleSubCommand());
     849
     850    VConfigPage page8(pages, false);
     851    page8->addChild(tvman);
     852
    779853    int page_num = 1;
    780854    for (ConfigPage::PageList::const_iterator p = pages.begin();
    781855         p != pages.end(); ++p, ++page_num)
  • mythplugins/mythvideo/mythvideo/videofilter.h

     
    5454        kOrderByUserRatingDescending = 2,
    5555        kOrderByLength = 3,
    5656        kOrderByFilename = 4,
    57         kOrderByID = 5
     57        kOrderByID = 5,
     58        kOrderBySeasonEp = 6
    5859    };
    5960
    6061    int GetCategory() const { return category; }
  • mythplugins/mythvideo/mythvideo/dbcheck.cpp

     
    3838    const QString lastMythDVDDBVersion = "1002";
    3939    const QString lastMythVideoVersion = "1010";
    4040
    41     const QString currentDatabaseVersion = "1023";
     41    const QString currentDatabaseVersion = "1024";
    4242
    4343    const QString OldMythVideoVersionName = "VideoDBSchemaVer";
    4444    const QString OldMythDVDVersionName = "DVDDBSchemaVer";
     
    834834            performActualUpdate(updates, "1023", dbver, MythVideoVersionName);
    835835        }
    836836
     837        if (dbver == "1023")
     838        {
     839            QStringList updates;
     840            updates += "ALTER TABLE videometadata ADD `subtitle` TEXT "
     841                       "NOT NULL AFTER `title`;";
     842            updates += "ALTER TABLE videometadata ADD `season` SMALLINT "
     843                       "UNSIGNED NOT NULL DEFAULT '0' AFTER `length`;";
     844            updates += "ALTER TABLE videometadata ADD `episode` SMALLINT "
     845                       "UNSIGNED NOT NULL DEFAULT '0' AFTER `season`;";
     846            performActualUpdate(updates, "1024", dbver, MythVideoVersionName);
     847        }
    837848
    838849    }
    839850}
  • mythplugins/mythvideo/mythvideo/videoutils.cpp

     
    139139    return QString("%1 minutes").arg(length);
    140140}
    141141
     142QString GetDisplaySeasonEpisode(int seasEp, int digits)
     143{
     144    QString seasEpNum = QString::number(seasEp);
     145
     146    if (digits == 2 && seasEpNum.size() < 2)
     147        seasEpNum.prepend("0");
     148       
     149    return seasEpNum;
     150}
     151
    142152QString GetDisplayBrowse(bool browse)
    143153{
    144154    return browse ? QObject::tr("Yes") : QObject::tr("No");
  • mythplugins/mythvideo/mythvideo/editmetadata.h

     
    1010class MythUIText;
    1111class MythUITextEdit;
    1212class MythUIButton;
     13class MythUISpinBox;
    1314class MythUICheckBox;
    1415
    1516class EditMetadataDialog : public MythScreenType
     
    3435  public slots:
    3536    void SaveAndExit();
    3637    void SetTitle();
     38    void SetSubtitle();
    3739    void SetCategory(MythUIButtonListItem*);
    3840    void SetPlayer();
     41    void SetSeason();
     42    void SetEpisode();
    3943    void SetLevel(MythUIButtonListItem*);
    4044    void SetChild(MythUIButtonListItem*);
    4145    void ToggleBrowse();
     
    6064    //
    6165
    6266    MythUITextEdit      *m_titleEdit;
     67    MythUITextEdit      *m_subtitleEdit;
    6368    MythUITextEdit      *m_playerEdit;
     69    MythUISpinBox       *m_seasonSpin;
     70    MythUISpinBox       *m_episodeSpin;
    6471    MythUIButtonList      *m_categoryList;
    6572    MythUIButtonList      *m_levelList;
    6673    MythUIButtonList      *m_childList;
  • mythplugins/mythvideo/mythvideo/videodlg.cpp

     
    288288        FanartDownloadErrorState m_error_state;
    289289    };
    290290
     291    class BannerDownloadProxy : public QObject
     292    {
     293        Q_OBJECT
     294
     295      signals:
     296        void SigFinished(BannerDownloadErrorState reason, QString errorMsg,
     297                         Metadata *item);
     298      public:
     299        static BannerDownloadProxy *Create(const QUrl &url, const QString &dest,
     300                                          Metadata *item)
     301        {
     302            return new BannerDownloadProxy(url, dest, item);
     303        }
     304
     305      public:
     306        void StartCopy()
     307        {
     308            m_id = m_http.get(m_url.toString(), &m_data_buffer);
     309
     310            m_timer.start(gContext->GetNumSetting("BannerDownloadTimeout", 30)
     311                          * 1000);
     312        }
     313
     314        void Stop()
     315        {
     316            if (m_timer.isActive())
     317                m_timer.stop();
     318
     319            VERBOSE(VB_GENERAL, tr("Banner download stopped."));
     320            m_http.abort();
     321        }
     322
     323      private:
     324        BannerDownloadProxy(const QUrl &url, const QString &dest,
     325                           Metadata *item) : m_item(item), m_dest_file(dest),
     326            m_id(0), m_url(url), m_error_state(besOK)
     327        {
     328            connect(&m_http, SIGNAL(requestFinished(int, bool)),
     329                    SLOT(OnFinished(int, bool)));
     330
     331            connect(&m_timer, SIGNAL(timeout()), SLOT(OnDownloadTimeout()));
     332            m_timer.setSingleShot(true);
     333            m_http.setHost(m_url.host());
     334        }
     335
     336        ~BannerDownloadProxy() {}
     337
     338      private slots:
     339        void OnDownloadTimeout()
     340        {
     341            VERBOSE(VB_IMPORTANT, QString("Copying of '%1' timed out")
     342                    .arg(m_url.toString()));
     343            m_error_state = besTimeout;
     344            Stop();
     345        }
     346
     347        void OnFinished(int id, bool error)
     348        {
     349            QString errorMsg;
     350            if (error)
     351                errorMsg = m_http.errorString();
     352
     353            if (id == m_id)
     354            {
     355                if (m_timer.isActive())
     356                    m_timer.stop();
     357
     358                if (!error)
     359                {
     360                    QFile dest_file(m_dest_file);
     361                    if (dest_file.exists())
     362                        dest_file.remove();
     363
     364                    if (dest_file.open(QIODevice::WriteOnly))
     365                    {
     366                        const QByteArray &data = m_data_buffer.data();
     367                        qint64 size = dest_file.write(data);
     368                        if (size != data.size())
     369                        {
     370                            errorMsg = tr("Error writing data to file %1.")
     371                                    .arg(m_dest_file);
     372                            m_error_state = besError;
     373                        }
     374                    }
     375                    else
     376                    {
     377                        errorMsg = tr("Error: file error '%1' for file %2").
     378                                arg(dest_file.errorString()).arg(m_dest_file);
     379                        m_error_state = besError;
     380                    }
     381                }
     382
     383                emit SigFinished(m_error_state, errorMsg, m_item);
     384            }
     385        }
     386
     387      private:
     388        Metadata *m_item;
     389        QHttp m_http;
     390        QBuffer m_data_buffer;
     391        QString m_dest_file;
     392        int m_id;
     393        QTimer m_timer;
     394        QUrl m_url;
     395        BannerDownloadErrorState m_error_state;
     396    };
     397
    291398    /** \class ExecuteExternalCommand
    292399     *
    293400     * \brief Base class for executing an external script or other process, must
     
    467574        void Run(QString title, Metadata *item)
    468575        {
    469576            m_item = item;
     577            int m_season, m_episode;
     578            QString cmd;
     579            m_season = m_item->GetSeason();
     580            m_episode = m_item->GetEpisode();
    470581
    471             QString def_cmd = QDir::cleanPath(QString("%1/%2")
     582            if (m_season > 0 || m_episode > 0)
     583            {
     584                const QString def_cmd = QDir::cleanPath(QString("%1/%2")
    472585                    .arg(GetShareDir())
     586                    .arg("mythvideo/scripts/ttvdb.py -M"));
     587                cmd = gContext->GetSetting("mythvideo.TVListCommandLine",
     588                                                        def_cmd);
     589            }
     590            else
     591            {
     592                QString def_cmd = QDir::cleanPath(QString("%1/%2")
     593                    .arg(GetShareDir())
    473594                    .arg("mythvideo/scripts/tmdb.pl -M"));
    474595
    475             QString cmd = gContext->GetSetting("MovieListCommandLine", def_cmd);
    476 
    477             QStringList args;
    478             args += title;
    479             StartRun(cmd, args, "Video Search");
     596                cmd = gContext->GetSetting("MovieListCommandLine", def_cmd);
     597            }
     598                QStringList args;
     599                args += title;
     600                StartRun(cmd, args, "Video Search");
    480601        }
    481602
    482603      private:
     
    505626        Metadata *m_item;
    506627    };
    507628
     629    /** \class VideoTitleSubtitleSearch
     630     *
     631     * \brief Executes the external command to do video title/subtitle searches.
     632     *
     633     */
     634    class VideoTitleSubtitleSearch : public ExecuteExternalCommand
     635    {
     636        Q_OBJECT
     637
     638      signals:
     639        void SigSearchResults(bool normal_exit, QStringList result,
     640                Metadata *item);
     641
     642      public:
     643        VideoTitleSubtitleSearch(QObject *oparent) :
     644            ExecuteExternalCommand(oparent), m_item(0) {}
     645
     646        void Run(QString title, QString subtitle, Metadata *item)
     647        {
     648            m_item = item;
     649            QString cmd;
     650
     651                const QString def_cmd = QDir::cleanPath(QString("%1/%2")
     652                    .arg(GetShareDir())
     653                    .arg("mythvideo/scripts/ttvdb.py -N"));
     654                cmd = gContext->GetSetting("mythvideo.TVTitleSubCommandLine",
     655                                                        def_cmd);
     656                QStringList args;
     657                args += title;
     658                args += subtitle;
     659                StartRun(cmd, args, "Video Search");
     660        }
     661
     662      private:
     663        ~VideoTitleSubtitleSearch() {}
     664
     665        void OnExecDone(bool normal_exit, QStringList out, QStringList err)
     666        {
     667            (void) err;
     668
     669            emit SigSearchResults(normal_exit, out, m_item);
     670            deleteLater();
     671        }
     672
     673      private:
     674        Metadata *m_item;
     675    };
     676
    508677    /** \class VideoUIDSearch
    509678     *
    510679     * \brief Execute the command to do video searches based on their ID.
     
    525694        void Run(QString video_uid, Metadata *item)
    526695        {
    527696            m_item = item;
    528             m_video_uid = video_uid;
     697            m_video_uid = video_uid;           
     698            int m_season, m_episode;
     699            m_season = m_item->GetSeason();
     700            m_episode = m_item->GetEpisode();
    529701
    530             const QString def_cmd = QDir::cleanPath(QString("%1/%2")
     702            if (m_season > 0 || m_episode > 0)
     703            {
     704                const QString def_cmd = QDir::cleanPath(QString("%1/%2")
    531705                    .arg(GetShareDir())
     706                    .arg("mythvideo/scripts/ttvdb.py -mD"));
     707                const QString cmd = gContext->GetSetting("mythvideo.TVDataCommandLine",
     708                                                        def_cmd);
     709                QStringList args;
     710                args << video_uid << QString::number(m_season)
     711                                  << QString::number(m_episode);
     712                StartRun(cmd, args, "Video Data Query");
     713            }
     714            else
     715            {
     716                const QString def_cmd = QDir::cleanPath(QString("%1/%2")
     717                    .arg(GetShareDir())
    532718                    .arg("mythvideo/scripts/tmdb.pl -D"));
    533             const QString cmd = gContext->GetSetting("MovieDataCommandLine",
     719                const QString cmd = gContext->GetSetting("MovieDataCommandLine",
    534720                                                        def_cmd);
    535 
    536             StartRun(cmd, QStringList(video_uid), "Video Data Query");
     721                StartRun(cmd, QStringList(video_uid), "Video Data Query");
     722            }
    537723        }
    538724
    539725      private:
     
    570756        void Run(QString video_uid, Metadata *item)
    571757        {
    572758            m_item = item;
     759            int m_season, m_episode;
     760            m_season = m_item->GetSeason();
     761            m_episode = m_item->GetEpisode();
    573762
    574             const QString default_cmd =
     763            if (m_season > 0 || m_episode > 0)
     764            {
     765                const QString def_cmd = QDir::cleanPath(QString("%1/%2")
     766                    .arg(GetShareDir())
     767                    .arg("mythvideo/scripts/ttvdb.py -mP"));
     768                const QString cmd = gContext->GetSetting("mythvideo.TVPosterCommandLine",
     769                                                        def_cmd);
     770                QStringList args;
     771                args << video_uid << QString::number(m_season)
     772                                  << QString::number(m_episode);
     773                StartRun(cmd, args, "Poster Query");
     774            }
     775            else
     776            {
     777                const QString default_cmd =
    575778                    QDir::cleanPath(QString("%1/%2")
    576779                                        .arg(GetShareDir())
    577780                                        .arg("mythvideo/scripts/tmdb.pl -P"));
    578             const QString cmd = gContext->GetSetting("MoviePosterCommandLine",
     781                const QString cmd = gContext->GetSetting("MoviePosterCommandLine",
    579782                                                        default_cmd);
    580             StartRun(cmd, QStringList(video_uid), "Poster Query");
     783
     784                StartRun(cmd, QStringList(video_uid), "Poster Query");
     785            }
    581786        }
    582787
    583788      private:
     
    627832        void Run(QString video_uid, Metadata *item)
    628833        {
    629834            m_item = item;
     835            int m_season, m_episode;
     836            m_season = m_item->GetSeason();
     837            m_episode = m_item->GetEpisode();
    630838
    631             const QString default_cmd =
     839            if (m_season > 0 || m_episode > 0)
     840            {
     841                const QString def_cmd = QDir::cleanPath(QString("%1/%2")
     842                    .arg(GetShareDir())
     843                    .arg("mythvideo/scripts/ttvdb.py -tF"));
     844                const QString cmd = gContext->GetSetting("mythvideo.TVFanartCommandLine",
     845                                                        def_cmd);
     846                QStringList args;
     847                args << video_uid << QString::number(m_season)
     848                                  << QString::number(m_episode);
     849                StartRun(cmd, args, "Fanart Query");
     850            }
     851            else
     852            {
     853                const QString default_cmd =
    632854                    QDir::cleanPath(QString("%1/%2")
    633855                                        .arg(GetShareDir())
    634856                                        .arg("mythvideo/scripts/tmdb.pl -B"));
    635             const QString cmd = gContext->GetSetting("MovieFanartCommandLine",
     857                const QString cmd = gContext->GetSetting("MovieFanartCommandLine",
    636858                                                        default_cmd);
    637             StartRun(cmd, QStringList(video_uid), "Fanart Query");
     859                StartRun(cmd, QStringList(video_uid), "Fanart Query");
     860            }
    638861        }
    639862
    640863      private:
     
    665888        Metadata *m_item;
    666889    };
    667890
     891    /** \class VideoBannerSearch
     892     *
     893     * \brief Execute external video banner command.
     894     *
     895     */
     896    class VideoBannerSearch : public ExecuteExternalCommand
     897    {
     898        Q_OBJECT
    668899
     900      signals:
     901        void SigBannerURL(QString url, Metadata *item);
     902
     903      public:
     904        VideoBannerSearch(QObject *oparent) :
     905            ExecuteExternalCommand(oparent), m_item(0) {}
     906
     907        void Run(QString video_uid, Metadata *item)
     908        {
     909            m_item = item;
     910            int m_season, m_episode;
     911            m_season = m_item->GetSeason();
     912            m_episode = m_item->GetEpisode();
     913
     914            const QString def_cmd = QDir::cleanPath(QString("%1/%2")
     915                    .arg(GetShareDir())
     916                    .arg("mythvideo/scripts/ttvdb.py -tB"));
     917            const QString cmd = gContext->GetSetting("mythvideo.TVBannerCommandLine",
     918                                                        def_cmd);
     919            QStringList args;
     920            args << video_uid << QString::number(m_season)
     921                                  << QString::number(m_episode);
     922            StartRun(cmd, args, "Banner Query");
     923        }
     924
     925      private:
     926        ~VideoBannerSearch() {}
     927
     928        void OnExecDone(bool normal_exit, QStringList out, QStringList err)
     929        {
     930            (void) err;
     931            QString url;
     932            if (normal_exit && out.size())
     933            {
     934                for (QStringList::const_iterator p = out.begin();
     935                        p != out.end(); ++p)
     936                {
     937                    if ((*p).length())
     938                    {
     939                        url = *p;
     940                        break;
     941                    }
     942                }
     943            }
     944
     945            emit SigBannerURL(url, m_item);
     946            deleteLater();
     947        }
     948
     949      private:
     950        Metadata *m_item;
     951    };
     952
    669953    class ParentalLevelNotifyContainer : public QObject
    670954    {
    671955        Q_OBJECT
     
    7901074        }
    7911075    };
    7921076
    793     bool GetLocalVideoPoster(const QString &video_uid, const QString &filename,
    794                              const QStringList &in_dirs, QString &poster)
     1077    bool GetLocalVideoImage(const QString &video_uid, const QString &filename,
     1078                             const QStringList &in_dirs, QString &image,
     1079                             QString title, int season)
    7951080    {
    7961081        QStringList search_dirs(in_dirs);
    7971082
     
    8211106                    ext != image_exts.end(); ++ext)
    8221107            {
    8231108                QStringList sfn;
     1109                if (season > 0)
     1110                    sfn += fntm.arg(*dir).arg(QString("%1 Season %2")
     1111                                 .arg(title).arg(QString::number(season)))
     1112                                 .arg(*ext);
    8241113                sfn += fntm.arg(*dir).arg(base_name).arg(*ext);
    8251114                sfn += fntm.arg(*dir).arg(video_uid).arg(*ext);
    8261115
     
    8291118                {
    8301119                    if (QFile::exists(*i))
    8311120                    {
    832                         poster = *i;
     1121                        image = *i;
    8331122                        return true;
    8341123                    }
    8351124                }
     
    10161305
    10171306            tmp["filename"] = metadata->GetFilename();
    10181307            tmp["title"] = metadata->GetTitle();
     1308            tmp["subtitle"] = metadata->GetSubtitle();
    10191309            tmp["director"] = metadata->GetDirector();
    10201310            tmp["plot"] = metadata->GetPlot();
    10211311            tmp["genres"] = GetDisplayGenres(*metadata);
     
    10251315            tmp["length"] = GetDisplayLength(metadata->GetLength());
    10261316            tmp["year"] = GetDisplayYear(metadata->GetYear());
    10271317            tmp["userrating"] = GetDisplayUserRating(metadata->GetUserRating());
     1318            tmp["season"] = GetDisplaySeasonEpisode(metadata->GetSeason(), 1);
     1319            tmp["episode"] = GetDisplaySeasonEpisode(metadata->GetEpisode(), 1);
    10281320
     1321            if (metadata->GetSeason() > 0 || metadata->GetEpisode() > 0)
     1322            {
     1323                tmp["s##e##"] = QString("s%1e%2").arg(GetDisplaySeasonEpisode
     1324                                                     (metadata->GetSeason(), 2))
     1325                                .arg(GetDisplaySeasonEpisode(metadata->GetEpisode(), 2));
     1326                tmp["##x##"] = QString("%1x%2").arg(GetDisplaySeasonEpisode
     1327                                                     (metadata->GetSeason(), 1))           
     1328                                .arg(GetDisplaySeasonEpisode(metadata->GetEpisode(), 2));
     1329            }
     1330            else
     1331                tmp["s##e##"] = tmp["##x##"] = "";
     1332
    10291333            tmp["userratingstate"] =
    10301334                    QString::number((int)(metadata->GetUserRating()));
    10311335            tmp["videolevel"] = ParentalLevelToState(metadata->GetShowLevel());
     
    10751379        h.handleText("player");
    10761380        h.handleText("filename");
    10771381        h.handleText("title");
     1382        h.handleText("subtitle");
    10781383        h.handleText("director");
    10791384        h.handleText("plot");
    10801385        h.handleText("genres");
     
    10821387        h.handleText("cast");
    10831388        h.handleText("rating");
    10841389        h.handleText("length");
     1390        h.handleText("season");
     1391        h.handleText("s##e##");
     1392        h.handleText("##x##");
     1393        h.handleText("episode");
    10851394        h.handleText("year");
    10861395        h.handleText("userrating");
    10871396
     
    12541563
    12551564        m_artDir = gContext->GetSetting("VideoArtworkDir");
    12561565        m_fanDir = gContext->GetSetting("mythvideo.fanartDir");
     1566        m_banDir = gContext->GetSetting("mythvideo.bannerDir");
    12571567    }
    12581568
    12591569    ~VideoDialogPrivate()
     
    13221632        }
    13231633    }
    13241634
     1635    void AddBannerDownload(BannerDownloadProxy *download)
     1636    {
     1637        m_running_bdownloads.insert(download);
     1638    }
     1639
     1640    void RemoveBannerDownload(BannerDownloadProxy *download)
     1641    {
     1642        if (download)
     1643        {
     1644            banner_download_list::iterator p =
     1645                    m_running_bdownloads.find(download);
     1646            if (p != m_running_bdownloads.end())
     1647                m_running_bdownloads.erase(p);
     1648        }
     1649    }
     1650
    13251651    void StopAllRunningCoverDownloads()
    13261652    {
    13271653        cover_download_list tmp(m_running_downloads);
     
    13361662            (*p)->Stop();
    13371663    }
    13381664
     1665    void StopAllRunningBannerDownloads()
     1666    {
     1667        banner_download_list tmp(m_running_bdownloads);
     1668        for (banner_download_list::iterator p = tmp.begin(); p != tmp.end(); ++p)
     1669            (*p)->Stop();
     1670    }
    13391671
    13401672  public:
    13411673    typedef std::set<CoverDownloadProxy *> cover_download_list;
    13421674    cover_download_list m_running_downloads;
    13431675    typedef std::set<FanartDownloadProxy *> fanart_download_list;
    13441676    fanart_download_list m_running_fdownloads;
     1677    typedef std::set<BannerDownloadProxy *> banner_download_list;
     1678    banner_download_list m_running_bdownloads;
    13451679    ParentalLevelNotifyContainer m_parentalLevel;
    13461680    bool m_switchingLayout;
    13471681
     
    13641698
    13651699    QString m_artDir;
    13661700    QString m_fanDir;
     1701    QString m_banDir;
    13671702    VideoScanner *m_scanner;
    13681703
    13691704    QString m_lastTreeNodePath;
     
    22732608
    22742609    m_menuPopup->SetReturnEvent(this, "manage");
    22752610
     2611    Metadata *metadata = GetMetadata(GetItemCurrent());
     2612
    22762613    m_menuPopup->AddButton(tr("Edit Metadata"), SLOT(EditMetadata()));
    22772614    m_menuPopup->AddButton(tr("Download Metadata"), SLOT(VideoSearch()));
     2615    m_menuPopup->AddButton(tr("Download TV by Title/Subtitle"), SLOT(TitleSubtitleSearch()));
     2616    if (metadata->GetInetRef() != VIDEO_INETREF_DEFAULT)
     2617        m_menuPopup->AddButton(tr("Download Images Only"),
     2618                          SLOT(ImageOnlyDownload()));
    22782619    m_menuPopup->AddButton(tr("Manually Enter Video #"),
    22792620            SLOT(ManualVideoUID()));
    22802621    m_menuPopup->AddButton(tr("Manually Enter Video Title"),
     
    25812922                                metadata);
    25822923}
    25832924
     2925void VideoDialog::TitleSubtitleSearch()
     2926{
     2927    Metadata *metadata = GetMetadata(GetItemCurrent());
     2928
     2929    if (metadata)
     2930        StartVideoSearchByTitleSubtitle(metadata->GetTitle(),
     2931                                metadata->GetSubtitle(), metadata);
     2932}
     2933
     2934void VideoDialog::ImageOnlyDownload()
     2935{
     2936    Metadata *metadata = GetMetadata(GetItemCurrent());
     2937
     2938    if (metadata->GetInetRef() != VIDEO_INETREF_DEFAULT)
     2939        StartVideoPosterSet(metadata);
     2940}
     2941
    25842942void VideoDialog::ToggleBrowseable()
    25852943{
    25862944    Metadata *metadata = GetMetadata(GetItemCurrent());
     
    27573115        metadata->Reset();
    27583116
    27593117        QString cover_file;
    2760         if (GetLocalVideoPoster(metadata->GetInetRef(), metadata->GetFilename(),
    2761                         QStringList(m_d->m_artDir), cover_file))
     3118        if (GetLocalVideoImage(metadata->GetInetRef(), metadata->GetFilename(),
     3119                        QStringList(m_d->m_artDir), cover_file,
     3120                        metadata->GetTitle(), metadata->GetSeason()))
    27623121        {
    27633122            metadata->SetCoverFile(cover_file);
    27643123        }
    27653124
     3125        QString fanart_file;
     3126        if (GetLocalVideoImage(metadata->GetInetRef(), metadata->GetFilename(),
     3127                        QStringList(m_d->m_fanDir), fanart_file,
     3128                        metadata->GetTitle(), metadata->GetSeason()))
     3129        {
     3130            metadata->SetFanart(fanart_file);
     3131        }
     3132
     3133        QString banner_file;
     3134        if (GetLocalVideoImage(metadata->GetInetRef(), metadata->GetFilename(),
     3135                        QStringList(m_d->m_banDir), banner_file,
     3136                        metadata->GetTitle(), metadata->GetSeason()))
     3137        {
     3138            metadata->SetBanner(banner_file);
     3139        }
     3140
    27663141        metadata->UpdateDatabase();
    27673142
    27683143        UpdateItem(item);
     
    27773152    //createBusyDialog(QObject::tr("Fetching poster for %1 (%2)")
    27783153    //                    .arg(metadata->InetRef())
    27793154    //                    .arg(metadata->Title()));
    2780     QStringList search_dirs;
    2781     search_dirs += m_d->m_artDir;
     3155    QStringList cover_dirs;
     3156    cover_dirs += m_d->m_artDir;
    27823157
    27833158    QString cover_file;
    27843159
    2785     if (GetLocalVideoPoster(metadata->GetInetRef(), metadata->GetFilename(),
    2786                             search_dirs, cover_file))
     3160    if (GetLocalVideoImage(metadata->GetInetRef(), metadata->GetFilename(),
     3161                            cover_dirs, cover_file, metadata->GetTitle(),
     3162                            metadata->GetSeason()))
    27873163    {
    27883164        metadata->SetCoverFile(cover_file);
    27893165        OnVideoPosterSetDone(metadata);
     
    27983174        vps->Run(metadata->GetInetRef(), metadata);
    27993175    }
    28003176
     3177    QStringList fanart_dirs;
     3178    fanart_dirs += m_d->m_fanDir;
     3179
     3180    QString fanart_file;
     3181
     3182    if (GetLocalVideoImage(metadata->GetInetRef(), metadata->GetFilename(),
     3183                            fanart_dirs, fanart_file, metadata->GetTitle(),
     3184                            metadata->GetSeason()))
     3185    {
     3186        metadata->SetFanart(fanart_file);
     3187        OnVideoFanartSetDone(metadata);
     3188    }
     3189
    28013190    if (metadata->GetFanart().isEmpty())
    28023191    {
    28033192        // Obtain video fanart
     
    28063195                SLOT(OnFanartURL(QString, Metadata *)));
    28073196        vfs->Run(metadata->GetInetRef(), metadata);
    28083197    }
     3198
     3199    QStringList banner_dirs;
     3200    banner_dirs += m_d->m_banDir;
     3201       
     3202    QString banner_file;
     3203       
     3204    if (GetLocalVideoImage(metadata->GetInetRef(), metadata->GetFilename(),
     3205                            banner_dirs, banner_file, metadata->GetTitle(),
     3206                            metadata->GetSeason()))
     3207    {
     3208        metadata->SetBanner(banner_file);
     3209        OnVideoBannerSetDone(metadata);
     3210    }
     3211
     3212    if (metadata->GetBanner().isEmpty() &&
     3213       (metadata->GetSeason() > 0 || metadata->GetEpisode() > 0))
     3214    {
     3215        // Obtain video banner (only for TV)
     3216        VideoBannerSearch *vbs = new VideoBannerSearch(this);
     3217        connect(vbs, SIGNAL(SigBannerURL(QString, Metadata *)),
     3218                SLOT(OnBannerURL(QString, Metadata *)));
     3219        vbs->Run(metadata->GetInetRef(), metadata);
     3220    }
    28093221}
    28103222
    28113223void VideoDialog::OnPosterURL(QString uri, Metadata *metadata)
     
    28383250            QUrl url(uri);
    28393251
    28403252            QString ext = QFileInfo(url.path()).suffix();
    2841             QString dest_file = QString("%1/%2.%3").arg(fileprefix)
    2842                     .arg(metadata->GetInetRef()).arg(ext);
     3253            QString dest_file;
     3254
     3255            if (metadata->GetSeason() > 0 ||
     3256                metadata->GetEpisode() > 0)
     3257            {
     3258                // Name TV downloads so that they already work with the PBB
     3259                QString title = QString("%1 Season %2").arg(metadata->GetTitle())
     3260                        .arg(metadata->GetSeason());
     3261                dest_file = QString("%1/%2.%3").arg(fileprefix)
     3262                        .arg(title).arg(ext);
     3263            }
     3264            else
     3265                dest_file = QString("%1/%2.%3").arg(fileprefix)
     3266                        .arg(metadata->GetInetRef()).arg(ext);
     3267
    28433268            VERBOSE(VB_IMPORTANT, QString("Copying '%1' -> '%2'...")
    28443269                    .arg(url.toString()).arg(dest_file));
    28453270
     
    29323357            QUrl url(uri);
    29333358
    29343359            QString ext = QFileInfo(url.path()).suffix();
    2935             QString dest_file = QString("%1/%2.%3").arg(fileprefix)
    2936                     .arg(metadata->GetInetRef()).arg(ext);
     3360            QString dest_file;
     3361
     3362            if (metadata->GetSeason() > 0 ||
     3363                metadata->GetEpisode() > 0)
     3364            {
     3365                // Name TV downloads so that they already work with the PBB   
     3366                QString title = QString("%1 Season %2").arg(metadata->GetTitle())
     3367                        .arg(metadata->GetSeason());
     3368                dest_file = QString("%1/%2.%3").arg(fileprefix)
     3369                        .arg(title).arg(ext);
     3370            }
     3371            else
     3372                dest_file = QString("%1/%2.%3").arg(fileprefix)
     3373                        .arg(metadata->GetInetRef()).arg(ext);
     3374
    29373375            VERBOSE(VB_IMPORTANT, QString("Copying '%1' -> '%2'...")
    29383376                    .arg(url.toString()).arg(dest_file));
    29393377
     
    29963434    UpdateItem(GetItemCurrent());
    29973435}
    29983436
     3437void VideoDialog::OnBannerURL(QString uri, Metadata *metadata)
     3438{
     3439    if (metadata)
     3440    {
     3441        if (uri.length())
     3442        {
     3443            QString fileprefix = m_d->m_banDir;
     3444
     3445            QDir dir;
     3446
     3447            // If the fanart setting hasn't been set default to
     3448            // using ~/.mythtv/MythVideo/Banners
     3449            if (fileprefix.length() == 0)
     3450            {
     3451                fileprefix = GetConfDir();
     3452
     3453                dir.setPath(fileprefix);
     3454                if (!dir.exists())
     3455                    dir.mkdir(fileprefix);
     3456
     3457                fileprefix += "/MythVideo/Banners";
     3458            }
     3459
     3460            dir.setPath(fileprefix);
     3461            if (!dir.exists())
     3462                dir.mkdir(fileprefix);
     3463
     3464            QUrl url(uri);
     3465
     3466            QString ext = QFileInfo(url.path()).suffix();
     3467            QString dest_file;
     3468
     3469            if (metadata->GetSeason() > 0 ||
     3470                metadata->GetEpisode() > 0)
     3471            {
     3472                // Name TV downloads so that they already work with the PBB   
     3473                QString title = QString("%1 Season %2").arg(metadata->GetTitle())
     3474                        .arg(metadata->GetSeason());
     3475                dest_file = QString("%1/%2.%3").arg(fileprefix)
     3476                        .arg(title).arg(ext);
     3477            }
     3478            else
     3479                dest_file = QString("%1/%2.%3").arg(fileprefix)
     3480                        .arg(metadata->GetInetRef()).arg(ext);
     3481
     3482            VERBOSE(VB_IMPORTANT, QString("Copying '%1' -> '%2'...")
     3483                    .arg(url.toString()).arg(dest_file));
     3484
     3485            BannerDownloadProxy *d =
     3486                    BannerDownloadProxy::Create(url, dest_file, metadata);
     3487            metadata->SetBanner(dest_file);
     3488
     3489            connect(d, SIGNAL(SigFinished(BannerDownloadErrorState,
     3490                                          QString, Metadata *)),
     3491                    SLOT(OnBannerCopyFinished(BannerDownloadErrorState,
     3492                                              QString, Metadata *)));
     3493
     3494            d->StartCopy();
     3495            m_d->AddBannerDownload(d);
     3496        }
     3497        else
     3498        {
     3499            metadata->SetBanner("");
     3500            OnVideoBannerSetDone(metadata);
     3501        }
     3502    }
     3503    else
     3504        OnVideoBannerSetDone(metadata);
     3505}
     3506
     3507void VideoDialog::OnBannerCopyFinished(BannerDownloadErrorState error,
     3508                                       QString errorMsg, Metadata *item)
     3509{
     3510    QObject *src = sender();
     3511    if (src)
     3512        m_d->RemoveBannerDownload(dynamic_cast<BannerDownloadProxy *>
     3513                                       (src));
     3514
     3515    if (error != besOK && item)
     3516        item->SetBanner("");
     3517
     3518    VERBOSE(VB_IMPORTANT, tr("Banner download finished: %1 %2")
     3519            .arg(errorMsg).arg(error));
     3520
     3521    if (error == besTimeout)
     3522    {
     3523        createOkDialog(tr("Banner exists for this item but could not be "
     3524                            "retrieved within the timeout period.\n"));
     3525    }
     3526
     3527    OnVideoBannerSetDone(item);
     3528}
     3529
     3530// This is the final call as part of a StartVideoBannerSet
     3531void VideoDialog::OnVideoBannerSetDone(Metadata *metadata)
     3532{
     3533    // The metadata has a banner set
     3534    if (m_busyPopup)
     3535    {
     3536        m_busyPopup->Close();
     3537        m_busyPopup = NULL;
     3538    }
     3539
     3540    metadata->UpdateDatabase();
     3541    UpdateItem(GetItemCurrent());
     3542}
     3543
    29993544void VideoDialog::StartVideoSearchByUID(QString video_uid, Metadata *metadata)
    30003545{
    30013546    // Starting the busy dialog here triggers a bizarre segfault
     
    30283573        }
    30293574        // set known values
    30303575        metadata->SetTitle(data["Title"]);
     3576        metadata->SetSubtitle(data["Subtitle"]);
    30313577        metadata->SetYear(data["Year"].toInt());
    30323578        metadata->SetDirector(data["Director"]);
    30333579        metadata->SetPlot(data["Plot"]);
    30343580        metadata->SetUserRating(data["UserRating"].toFloat());
    30353581        metadata->SetRating(data["MovieRating"]);
    30363582        metadata->SetLength(data["Runtime"].toInt());
     3583        metadata->SetSeason(data["Season"].toInt());
     3584        metadata->SetEpisode(data["Episode"].toInt());
    30373585
    30383586        m_d->AutomaticParentalAdjustment(metadata);
    30393587
     
    31663714    }
    31673715}
    31683716
     3717void VideoDialog::StartVideoSearchByTitleSubtitle(QString title,
     3718                                            QString subtitle, Metadata *metadata)
     3719{
     3720        createBusyDialog(title);
     3721
     3722        VideoTitleSubtitleSearch *vtss = new VideoTitleSubtitleSearch(this);
     3723
     3724        connect(vtss, SIGNAL(SigSearchResults(bool, QStringList,
     3725                                Metadata *)),
     3726                SLOT(OnVideoSearchByTitleSubtitleDone(bool, QStringList,
     3727                                Metadata *)));
     3728        vtss->Run(title, subtitle, metadata);
     3729}
     3730
     3731void VideoDialog::OnVideoSearchByTitleSubtitleDone(bool normal_exit,
     3732        QStringList result, Metadata *metadata)
     3733{
     3734    if (m_busyPopup)
     3735    {
     3736        m_busyPopup->Close();
     3737        m_busyPopup = NULL;
     3738    }
     3739
     3740    (void) normal_exit;
     3741
     3742    QString SeasEp = result.takeAt(0);
     3743
     3744    if (!SeasEp.isEmpty())
     3745    {
     3746
     3747        // Stuff to parse Season and Episode here
     3748        QString season, episode = NULL;
     3749
     3750        QRegExp group("(?:[s])?(\\d{1,3})(?:\\s|-)?(?:[ex])" //Season
     3751                      "(?:\\s|-)?(\\d{1,3})", // Episode
     3752                      Qt::CaseInsensitive);
     3753
     3754        int pos = group.indexIn(SeasEp);
     3755        if (pos > -1)
     3756        {
     3757        QString groupResult = group.cap(0);
     3758        season = group.cap(1);
     3759        episode = group.cap(2);
     3760        }
     3761
     3762        VERBOSE(VB_IMPORTANT,
     3763            QString("Season and Episode found!  It was: %1")
     3764            .arg(SeasEp));
     3765
     3766        if (!season.isNull() && !episode.isNull());
     3767        {
     3768            metadata->SetSeason(season.toInt());
     3769            metadata->SetEpisode(episode.toInt());
     3770            StartVideoSearchByTitle(VIDEO_INETREF_DEFAULT,
     3771                                metadata->GetTitle(), metadata);
     3772        }
     3773    }
     3774    else
     3775        createOkDialog(tr("No matches were found."));
     3776}
     3777
    31693778void VideoDialog::doVideoScan()
    31703779{
    31713780    if (!m_d->m_scanner)
  • mythplugins/mythvideo/mythvideo/videolist.cpp

     
    12671267            QString title = qfi.completeBaseName();
    12681268            if (m_infer_title)
    12691269            {
    1270                 QString tmptitle(Metadata::FilenameToTitle(file_string));
     1270                QString tmptitle(Metadata::FilenameToMeta(file_string, 1));
    12711271                if (tmptitle.length())
    12721272                    title = tmptitle;
    12731273            }
  • mythplugins/mythvideo/mythvideo/videoscan.cpp

     
    267267                                 VIDEO_SCREENSHOT_DEFAULT,
    268268                                 VIDEO_BANNER_DEFAULT,
    269269                                 VIDEO_FANART_DEFAULT,
    270                                  Metadata::FilenameToTitle(p->first),
     270                                 Metadata::FilenameToMeta(p->first, 1),
     271                                 Metadata::FilenameToMeta(p->first, 4),
    271272                                 VIDEO_YEAR_DEFAULT,
    272273                                 VIDEO_INETREF_DEFAULT, VIDEO_DIRECTOR_DEFAULT,
    273                                  VIDEO_PLOT_DEFAULT, 0.0, VIDEO_RATING_DEFAULT,
    274                                  0, 0, ParentalLevel::plLowest);
     274                                 VIDEO_PLOT_DEFAULT, 0.0, VIDEO_RATING_DEFAULT, 0,
     275                                 Metadata::FilenameToMeta(p->first, 2).toInt(),
     276                                 Metadata::FilenameToMeta(p->first, 3).toInt(),
     277                                 0, ParentalLevel::plLowest);
    275278
    276279                VERBOSE(VB_GENERAL, QString("Adding : %1 : %2")
    277280                        .arg(newFile.GetHost()).arg(newFile.GetFilename()));
  • mythplugins/mythvideo/mythvideo/videofilter.cpp

     
    353353            ret = lhs_key < rhs_key;
    354354            break;
    355355        }
     356        case kOrderBySeasonEp:
     357        {
     358            if ((lhs.GetSeason() == rhs.GetSeason())
     359                && (lhs.GetEpisode() == rhs.GetEpisode())
     360                && (lhs.GetSeason() == 0)
     361                && (rhs.GetSeason() == 0)
     362                && (lhs.GetEpisode() == 0)
     363                && (rhs.GetEpisode() == 0))
     364            {
     365                Metadata::SortKey lhs_key;
     366                Metadata::SortKey rhs_key;
     367                if (lhs.HasSortKey() && rhs.HasSortKey())
     368                {
     369                    lhs_key = lhs.GetSortKey();
     370                    rhs_key = rhs.GetSortKey();
     371                }
     372                else
     373                {
     374                    lhs_key = Metadata::GenerateDefaultSortKey(lhs,
     375                                                               sort_ignores_case);
     376                    rhs_key = Metadata::GenerateDefaultSortKey(rhs,
     377                                                               sort_ignores_case);
     378                }
     379                ret = lhs_key < rhs_key;
     380            }
     381            else if (lhs.GetSeason() == rhs.GetSeason()
     382                     && lhs.GetTitle() == rhs.GetTitle())
     383                ret = lhs.GetEpisode() < rhs.GetEpisode();
     384            else
     385                ret = lhs.GetSeason() < rhs.GetSeason();
     386            break;
     387        }
    356388        case kOrderByYearDescending:
    357389        {
    358390            ret = lhs.GetYear() > rhs.GetYear();
     
    649681    // Order by
    650682    new MythUIButtonListItem(m_orderbyList, QObject::tr("Title"),
    651683                           VideoFilterSettings::kOrderByTitle);
     684    new MythUIButtonListItem(m_orderbyList, QObject::tr("Season/Episode"),
     685                           VideoFilterSettings::kOrderBySeasonEp);
    652686    new MythUIButtonListItem(m_orderbyList, QObject::tr("Year"),
    653687                           VideoFilterSettings::kOrderByYearDescending);
    654688    new MythUIButtonListItem(m_orderbyList, QObject::tr("User Rating"),
  • mythplugins/mythvideo/mythvideo/metadata.h

     
    1313
    1414enum { VIDEO_YEAR_DEFAULT = 1895 };
    1515
     16const QString VIDEO_SUBTITLE_DEFAULT = "";
     17
    1618struct SortData;
    1719
    1820class Metadata
     
    4446
    4547  public:
    4648    static SortKey GenerateDefaultSortKey(const Metadata &m, bool ignore_case);
    47     static QString FilenameToTitle(const QString &file_name);
     49    static QString FilenameToMeta(const QString &file_name, int position);
    4850    static QString TrimTitle(const QString &title, bool ignore_case);
    4951
    5052  public:
     
    5557             const QString &banner = QString(),
    5658             const QString &fanart = QString(),
    5759             const QString &title = QString(),
     60             const QString &subtitle = QString(),
    5861             int year = VIDEO_YEAR_DEFAULT,
    5962             const QString &inetref = QString(),
    6063             const QString &director = QString(),
     
    6265             float userrating = 0.0,
    6366             const QString &rating = QString(),
    6467             int length = 0,
     68             int season = 0,
     69             int episode = 0,
    6570             int id = 0,
    6671             ParentalLevel::Level showlevel = ParentalLevel::plLowest,
    6772             int categoryID = 0,
     
    8994    const QString &GetTitle() const;
    9095    void SetTitle(const QString& title);
    9196
     97    const QString &GetSubtitle() const;
     98    void SetSubtitle(const QString &subtitle);
     99
    92100    int GetYear() const;
    93101    void SetYear(int year);
    94102
     
    110118    int GetLength() const;
    111119    void SetLength(int length);
    112120
     121    int GetSeason() const;
     122    void SetSeason(int season);
     123
     124    int GetEpisode() const;
     125    void SetEpisode(int episode);
     126
    113127    unsigned int GetID() const;
    114128    void SetID(int id);
    115129
  • mythplugins/mythvideo/mythvideo/editmetadata.cpp

     
    1212#include <mythtv/libmythui/mythuitextedit.h>
    1313#include <mythtv/libmythui/mythuibutton.h>
    1414#include <mythtv/libmythui/mythuicheckbox.h>
     15#include <mythtv/libmythui/mythuispinbox.h>
    1516
    1617#include "globals.h"
    1718#include "dbaccess.h"
     
    2223EditMetadataDialog::EditMetadataDialog(MythScreenStack *lparent,
    2324        QString lname, Metadata *source_metadata,
    2425        const MetadataListManager &cache) : MythScreenType(lparent, lname),
    25     m_origMetadata(source_metadata), m_titleEdit(0), m_playerEdit(0),
    26     m_categoryList(0), m_levelList(0), m_childList(0), m_browseCheck(0),
    27     m_coverartButton(0), m_coverartText(0),
     26    m_origMetadata(source_metadata), m_titleEdit(0), m_subtitleEdit(0),
     27    m_playerEdit(0), m_seasonSpin(0), m_episodeSpin(0),
     28    m_categoryList(0), m_levelList(0), m_childList(0),
     29    m_browseCheck(0), m_coverartButton(0), m_coverartText(0),
    2830    m_screenshotButton(0), m_screenshotText(0),
    2931    m_bannerButton(0), m_bannerText(0),
    3032    m_fanartButton(0), m_fanartText(0),
     
    4749
    4850    bool err = false;
    4951    UIUtilE::Assign(this, m_titleEdit, "title_edit", &err);
     52    UIUtilE::Assign(this, m_subtitleEdit, "subtitle_edit", &err);
    5053    UIUtilE::Assign(this, m_playerEdit, "player_edit", &err);
    5154
     55    UIUtilE::Assign(this, m_seasonSpin, "season", &err);
     56    UIUtilE::Assign(this, m_episodeSpin, "episode", &err);
     57
    5258    UIUtilE::Assign(this, m_coverartText, "coverart_text", &err);
    5359    UIUtilE::Assign(this, m_screenshotText, "screenshot_text", &err);
    5460    UIUtilE::Assign(this, m_bannerText, "banner_text", &err);
     
    7985        VERBOSE(VB_IMPORTANT, "Failed to build a focuslist.");
    8086
    8187    connect(m_titleEdit, SIGNAL(valueChanged()), SLOT(SetTitle()));
     88    connect(m_subtitleEdit, SIGNAL(valueChanged()), SLOT(SetSubtitle()));
    8289    connect(m_playerEdit, SIGNAL(valueChanged()), SLOT(SetPlayer()));
    8390
     91    connect(m_seasonSpin, SIGNAL(LosingFocus()), SLOT(SetSeason()));
     92    connect(m_episodeSpin, SIGNAL(LosingFocus()), SLOT(SetEpisode()));
     93
    8494    connect(m_doneButton, SIGNAL(Clicked()), SLOT(SaveAndExit()));
    8595    connect(m_coverartButton, SIGNAL(Clicked()), SLOT(FindCoverArt()));
    8696    connect(m_bannerButton, SIGNAL(Clicked()), SLOT(FindBanner()));
     
    154164void EditMetadataDialog::fillWidgets()
    155165{
    156166    m_titleEdit->SetText(m_workingMetadata->GetTitle());
     167    m_subtitleEdit->SetText(m_workingMetadata->GetSubtitle());
    157168
     169    m_seasonSpin->SetRange(0,100,1);
     170    m_seasonSpin->SetValue(m_workingMetadata->GetSeason());
     171    m_episodeSpin->SetRange(0,999,1);
     172    m_episodeSpin->SetValue(m_workingMetadata->GetEpisode());
     173
    158174    MythUIButtonListItem *button =
    159175        new MythUIButtonListItem(m_categoryList, VIDEO_CATEGORY_UNKNOWN);
    160176    const VideoCategory::entry_list &vcl =
     
    312328    m_workingMetadata->SetTitle(m_titleEdit->GetText());
    313329}
    314330
     331void EditMetadataDialog::SetSubtitle()
     332{
     333    m_workingMetadata->SetSubtitle(m_subtitleEdit->GetText());
     334}
     335
    315336void EditMetadataDialog::SetCategory(MythUIButtonListItem *item)
    316337{
    317338    m_workingMetadata->SetCategoryID(item->GetData().toInt());
    318339}
    319340
     341void EditMetadataDialog::SetSeason()
     342{
     343    m_workingMetadata->SetSeason(m_seasonSpin->GetIntValue());
     344}
     345
     346void EditMetadataDialog::SetEpisode()
     347{
     348    m_workingMetadata->SetEpisode(m_episodeSpin->GetIntValue());
     349}
     350
    320351void EditMetadataDialog::SetPlayer()
    321352{
    322353    m_workingMetadata->SetPlayCommand(m_playerEdit->GetText());
  • mythplugins/mythvideo/mythvideo/playercommand.cpp

     
    237237            play_command = "Internal";
    238238
    239239        QString plot;
    240         QString title = Metadata::FilenameToTitle(filename);
     240        QString title = Metadata::FilenameToMeta(filename, 1);
    241241        QString director;
    242242        int length = 0;
    243243        QString year = QString::number(VIDEO_YEAR_DEFAULT);
  • mythplugins/mythvideo/mythvideo/videoutils.h

     
    3333
    3434QString GetDisplayUserRating(float userrating);
    3535QString GetDisplayLength(int length);
     36QString GetDisplaySeasonEpisode(int seasEp, int digits);
    3637QString GetDisplayBrowse(bool browse);
    3738QString GetDisplayYear(int year);
    3839QString GetDisplayRating(const QString &rating);
  • mythtv/themes/Terra/video-ui.xml

     
    565565        </imagetype>
    566566
    567567        <textarea name="title" from="basetextarea">
    568             <area>48,78,980,35</area>
     568            <area>48,78,590,35</area>
    569569            <font>baselarge</font>
    570570        </textarea>
    571571
     572        <textarea name="subtitle" from="basetextarea">
     573            <area>600,78,590,35</area>
     574            <align>right</align>
     575            <font>baselarge</font>
     576        </textarea>
     577
    572578        <statetype name="userratingstate" from="baserating">
    573579            <position>1193,72</position>
    574580        </statetype>
     
    583589            <area>48,284,290,30</area>
    584590        </textarea>
    585591
     592        <textarea name="##x##" from="basetextarea">
     593            <area>540,284,200,30</area>
     594            <align>center</align>
     595        </textarea>
     596
    586597        <textarea name="director" from="basetextarea">
    587598            <area>430,284,800,30</area>
    588599            <align>right</align>
     
    885896        <!-- Labels  -->
    886897
    887898        <textarea name="title_text" from="basetextarea">
    888             <area>50,135,250,40</area>
    889             <value>Name:</value>
     899            <area>150,80,250,40</area>
     900            <value>Title:</value>
    890901            <align>right,top</align>
    891902        </textarea>
    892903
     904        <textarea name="subtitle_text" from="basetextarea">
     905            <area>150,138,250,40</area>
     906            <value>Subtitle:</value>
     907            <align>right,top</align>
     908        </textarea>
     909
     910        <textarea name="season_text" from="basetextarea">
     911            <area>200,185,250,40</area>
     912            <value>Season:</value>
     913            <align>right,top</align>
     914        </textarea>
     915
     916        <textarea name="episode_text" from="basetextarea">
     917            <area>520,185,150,40</area>
     918            <value>Episode:</value>
     919            <align>right,top</align>
     920        </textarea>
     921
    893922        <textarea name="category_text" from="title_text">
    894             <position>50,197</position>
     923            <area>520,232,150,40</area>
     924            <align>right</align>
    895925            <value>Category:</value>
    896926        </textarea>
    897927
    898928        <textarea name="level_text" from="title_text">
    899             <position>50,247</position>
     929            <area>120,232,200,40</area>
     930            <align>right</align>
    900931            <value>Parental Control:</value>
    901932        </textarea>
    902933
    903934        <textarea name="child_text" from="title_text">
    904             <position>50,292</position>
     935            <area>120,277,200,40</area>
     936            <align>right</align>
    905937            <value>File to Always Play Next:</value>
    906938        </textarea>
    907939
    908940        <textarea name="browse_text" from="title_text">
    909             <position>50,337</position>
     941            <area>570,277,280,40</area>
     942            <align>left</align>
    910943            <value>Include while Browsing:</value>
    911944        </textarea>
    912945
    913946        <textarea name="coverart_text_label" from="title_text">
    914             <position>50,375</position>
     947            <position>200,328</position>
    915948            <value>Cover Art:</value>
    916949        </textarea>
    917950
     951        <textarea name="screenshot_text_label" from="title_text">
     952            <position>200,357</position>
     953            <value>Screenshot:</value>
     954        </textarea>
     955
     956        <textarea name="banner_text_label" from="title_text">
     957            <position>200,386</position>
     958            <value>Banner:</value>
     959        </textarea>
     960
     961        <textarea name="fanart_text_label" from="title_text">
     962            <position>200,415</position>
     963            <value>Fanart:</value>
     964        </textarea>
     965
    918966        <textarea name="trailer_text_label" from="title_text">
    919             <position>50,405</position>
     967            <position>200,447</position>
    920968            <value>Trailer:</value>
    921969        </textarea>
    922970
    923971        <textarea name="player_text" from="title_text">
    924             <position>50,445</position>
     972            <position>150,487</position>
    925973            <value>Unique Player Command:</value>
    926974        </textarea>
    927975
    928976        <!-- Widgets -->
    929977
    930978        <textedit name="title_edit" from="basetextedit">
    931             <position>310,125</position>
     979            <position>410,70</position>
    932980        </textedit>
    933981
    934         <buttonlist name="category_select" from="baseselector">
    935             <position>310,190</position>
    936         </buttonlist>
     982        <textedit name="subtitle_edit" from="basetextedit">
     983            <position>410,126</position>
     984        </textedit>
    937985
     986        <spinbox name="season" from="basespinbox">
     987            <position>460,181</position>
     988        </spinbox>
     989
     990        <spinbox name="episode" from="basespinbox">
     991            <position>680,181</position>
     992        </spinbox>
     993
    938994        <buttonlist name="level_select" from="baseselector">
    939             <position>310,240</position>
     995            <position>330,225</position>
    940996        </buttonlist>
    941997
     998        <buttonlist name="category_select" from="baseselector">
     999            <position>680,225</position>
     1000        </buttonlist>
     1001
    9421002        <buttonlist name="child_select" from="baseselector">
    943             <position>310,285</position>
     1003            <position>330,270</position>
    9441004        </buttonlist>
    9451005
    9461006        <checkbox name="browse_check" from="basecheckbox">
    947             <position>310,335</position>
     1007            <position>835,275</position>
    9481008        </checkbox>
    9491009
    9501010        <button name="coverart_button">
    951             <area>310,370,32,32</area>
     1011            <area>460,323,32,32</area>
    9521012            <statetype name="buttonstate">
    9531013                <state name="active">
    9541014                    <imagetype name="background">
     
    9701030        </button>
    9711031
    9721032        <textarea name="coverart_text" from="basetextarea">
    973             <area>350,375,250,40</area>
     1033            <area>500,328,250,40</area>
    9741034            <value>/path/to/the/thing.jpg</value>
    9751035        </textarea>
    9761036
     1037        <button name="screenshot_button">
     1038            <area>460,352,32,32</area>
     1039            <statetype name="buttonstate">
     1040                <state name="active">
     1041                    <imagetype name="background">
     1042                        <filename>blankbutton_off.png</filename>
     1043                    </imagetype>
     1044                </state>
     1045                <state name="selected" from="active">
     1046                    <imagetype name="background">
     1047                        <filename>blankbutton_on.png</filename>
     1048                    </imagetype>
     1049                </state>
     1050                <state name="disabled" from="active" />
     1051                <state name="pushed" from="active">
     1052                    <imagetype name="background">
     1053                        <filename>blankbutton_pushed.png</filename>
     1054                    </imagetype>
     1055                </state>
     1056            </statetype>
     1057        </button>
     1058
     1059        <textarea name="screenshot_text" from="basetextarea">
     1060            <area>500,357,250,40</area>
     1061            <value>/path/to/the/thing.jpg</value>
     1062        </textarea>
     1063
     1064        <button name="banner_button">
     1065            <area>460,381,32,32</area>
     1066            <statetype name="buttonstate">
     1067                <state name="active">
     1068                    <imagetype name="background">
     1069                        <filename>blankbutton_off.png</filename>
     1070                    </imagetype>
     1071                </state>
     1072                <state name="selected" from="active">
     1073                    <imagetype name="background">
     1074                        <filename>blankbutton_on.png</filename>
     1075                    </imagetype>
     1076                </state>
     1077                <state name="disabled" from="active" />
     1078                <state name="pushed" from="active">
     1079                    <imagetype name="background">
     1080                        <filename>blankbutton_pushed.png</filename>
     1081                    </imagetype>
     1082                </state>
     1083            </statetype>
     1084        </button>
     1085
     1086        <textarea name="banner_text" from="basetextarea">
     1087            <area>500,386,250,40</area>
     1088            <value>/path/to/the/thing.jpg</value>
     1089        </textarea>
     1090
     1091        <button name="fanart_button">
     1092            <area>460,412,32,32</area>
     1093            <statetype name="buttonstate">
     1094                <state name="active">
     1095                    <imagetype name="background">
     1096                        <filename>blankbutton_off.png</filename>
     1097                    </imagetype>
     1098                </state>
     1099                <state name="selected" from="active">
     1100                    <imagetype name="background">
     1101                        <filename>blankbutton_on.png</filename>
     1102                    </imagetype>
     1103                </state>
     1104                <state name="disabled" from="active" />
     1105                <state name="pushed" from="active">
     1106                    <imagetype name="background">
     1107                        <filename>blankbutton_pushed.png</filename>
     1108                    </imagetype>
     1109                </state>
     1110            </statetype>
     1111        </button>
     1112
     1113        <textarea name="fanart_text" from="basetextarea">
     1114            <area>500,415,250,40</area>
     1115            <value>/path/to/the/thing.jpg</value>
     1116        </textarea>
     1117
    9771118        <button name="trailer_button">
    978             <area>310,400,32,32</area>
     1119            <area>460,442,32,32</area>
    9791120            <statetype name="buttonstate">
    9801121                <state name="active">
    9811122                    <imagetype name="background">
     
    9971138        </button>
    9981139
    9991140        <textarea name="trailer_text" from="basetextarea">
    1000             <area>350,405,250,40</area>
     1141            <area>500,447,250,40</area>
    10011142            <value>/path/to/the/thing.jpg</value>
    10021143        </textarea>
    10031144
     1145
    10041146        <textedit name="player_edit" from="basetextedit">
    1005             <position>310,435</position>
     1147            <position>410,477</position>
    10061148        </textedit>
    10071149
    10081150        <button name="done_button" from="basebutton">
    1009             <position>310,505</position>
     1151            <position>510,537</position>
     1152            <value>Done</value>
    10101153        </button>
    10111154
    10121155    </window>
  • mythtv/programs/mythfrontend/playbackbox.cpp

     
    2020#include "mythdirs.h"
    2121#include "mythcontext.h"
    2222#include "mythdbcon.h"
     23#include "mythdb.h"
    2324#include "mythverbose.h"
    2425#include "programinfo.h"
    2526#include "scheduledrecording.h"
     
    3536#include "mythuibutton.h"
    3637#include "mythuibuttonlist.h"
    3738#include "mythuistatetype.h"
     39#include "mythuispinbox.h"
    3840#include "mythdialogbox.h"
    3941#include "mythuitextedit.h"
    4042#include "mythuiimage.h"
    4143#include "mythuicheckbox.h"
    4244#include "mythuiprogressbar.h"
     45#include "mythprogressdialog.h"
    4346
    4447#define LOC QString("PlaybackBox: ")
    4548#define LOC_ERR QString("PlaybackBox Error: ")
     
    5154
    5255#define USE_PREV_GEN_THREAD
    5356
     57QString customExportFile;
     58QString customExportDir;
     59unsigned int seasonValue = 0;
     60unsigned int episodeValue = 0;
     61unsigned int customExportSeason = 0;
     62unsigned int customExportEpisode = 0;
     63
    5464const uint PreviewGenState::maxAttempts     = 5;
    5565const uint PreviewGenState::minBlockSeconds = 60;
    5666
     
    18121822    RemoteStopRecording(rec);
    18131823}
    18141824
     1825void PlaybackBox::mvexport(ProgramInfo *rec)
     1826{
     1827
     1828    // User Rating Adjustment
     1829    QString exportRating = QString::number((int)((rec->stars * 10.0) + 0.5));
     1830
     1831    // Stuff necessary to perform the copy command
     1832
     1833    QString copyFrom = rec->GetPlaybackURL(false, true);
     1834    QString baseMVDir = gContext->GetSetting("VideoStartupDir");
     1835    QString MVFileFormat;
     1836    QString MVDirFormat;
     1837    QString copyToDir;
     1838    QString copyToFile;
     1839    QString extension;
     1840
     1841    // Check the original extension
     1842
     1843    QRegExp rx(".*\\.(\\w+)$");
     1844    int pos = rx.indexIn(copyFrom);
     1845    if (pos > -1)
     1846    {
     1847        extension = rx.cap(1);
     1848    }
     1849    else
     1850    {
     1851        extension = "";
     1852    }
     1853
     1854    // If a custom export string is used, use it.
     1855    // Also replace %VARIABLES% with actual values.
     1856
     1857    if (customExportFile.isEmpty() && customExportDir.isEmpty()
     1858        && customExportSeason == 0 && customExportEpisode == 0)
     1859    {
     1860        // Season-Episode must come first for replace to work right.
     1861        QString recType = rec->catType;
     1862        if (recType == "movie")
     1863        {
     1864            seasonValue = 0;
     1865            episodeValue = 0;
     1866        }
     1867        else
     1868        {
     1869            seasonValue = getLastSeason(rec->title);
     1870            episodeValue = (getLastEpisode(rec->title, seasonValue) + 1);
     1871        }
     1872
     1873        QString defaultDir = gContext->GetSetting("mythvideo.TVExportDirFormat",
     1874                              "Television/%TITLE%/");
     1875        QString defaultFile = gContext->GetSetting("mythvideo.TVExportFileFormat",
     1876                              "%TITLE% %##X##% - %SUBTITLE%");
     1877        MVDirFormat = replaceExportVariables(rec, defaultDir);
     1878        MVFileFormat = replaceExportVariables(rec, defaultFile);
     1879    }
     1880    else
     1881    {
     1882        seasonValue = customExportSeason;
     1883        episodeValue = customExportEpisode;
     1884        MVDirFormat = replaceExportVariables(rec, customExportDir);
     1885        MVFileFormat = replaceExportVariables(rec, customExportFile);
     1886    }
     1887
     1888    copyToDir = QString("%1/%2").arg(baseMVDir).arg(MVDirFormat);
     1889    copyToFile = QString("%1/%2.%3").arg(copyToDir)
     1890                         .arg(MVFileFormat).arg(extension);
     1891
     1892    // replace double slash with single
     1893
     1894    copyToFile.replace("//", "/");
     1895
     1896    // File and Directory Definitions
     1897
     1898    QFile fromFile(copyFrom);
     1899    QDir toDir(copyToDir);
     1900    QFile toFile(copyToFile);
     1901
     1902    if (!toDir.exists())
     1903    {
     1904        // Attempt to create path to export point.
     1905        toDir.mkpath(copyToDir);
     1906        toDir.mkdir(copyToDir);
     1907        if (!toDir.exists())
     1908        {
     1909            VERBOSE(VB_IMPORTANT, QString("Unable to create directory %1! "
     1910                                          "Please ensure the preceding path "
     1911                                          "exists and is writeable.").arg(copyToDir));   
     1912            return;
     1913        }
     1914    }
     1915
     1916    // Perform the actual copy.
     1917
     1918    long long int bytesCopied = copy(toFile,fromFile);
     1919
     1920    if (bytesCopied != -1)
     1921    {
     1922        // Add File into videometadata
     1923
     1924        MSqlQuery query(MSqlQuery::InitCon());
     1925
     1926        query.prepare("INSERT INTO videometadata (title,subtitle,director,"
     1927                          "plot,rating,year,userrating,length,season,"
     1928                          "episode,filename,showlevel,coverfile,inetref,"
     1929                          "browse, trailer, screenshot, banner, fanart) VALUES "
     1930                          "(:TITLE, :SUBTITLE, :DIRECTOR, :PLOT, :RATING, :YEAR, "
     1931                          ":USERRATING, :LENGTH, :SEASON, :EPISODE, :FILENAME, "
     1932                          ":SHOWLEVEL, :COVERFILE, :INETREF, :BROWSE, :TRAILER, "
     1933                          ":SCREENSHOT, :BANNER, :FANART)");
     1934
     1935        query.bindValue(":TITLE", rec->title);
     1936        query.bindValue(":SUBTITLE", rec->subtitle);
     1937        query.bindValue(":DIRECTOR", "Unknown");
     1938        query.bindValue(":PLOT", rec->description);
     1939        query.bindValue(":RATING", "NR");
     1940        query.bindValue(":YEAR", rec->originalAirDate.toString("yyyy"));
     1941        query.bindValue(":USERRATING", exportRating);
     1942        query.bindValue(":LENGTH", (rec->startts.secsTo(rec->endts) / 60));
     1943        query.bindValue(":SEASON", seasonValue);
     1944        query.bindValue(":EPISODE", episodeValue);   
     1945        query.bindValue(":FILENAME", copyToFile);
     1946        query.bindValue(":SHOWLEVEL", 1);
     1947        query.bindValue(":COVERFILE", "No Cover");
     1948        query.bindValue(":INETREF", QString::number(getLastInetref(rec->title)));
     1949        query.bindValue(":BROWSE", 1);
     1950        query.bindValue(":TRAILER", "");
     1951        query.bindValue(":SCREENSHOT", "");
     1952        query.bindValue(":BANNER", "");
     1953        query.bindValue(":FANART", "");
     1954
     1955        if (!query.exec() || !query.isActive())
     1956        {
     1957            MythDB::DBError("video metadata update", query);
     1958            return;
     1959        }
     1960
     1961        // Move recordedmarkup for file into videometadata
     1962
     1963        MSqlQuery markup(MSqlQuery::InitCon());
     1964
     1965        markup.prepare("INSERT INTO filemarkup (filename,mark,offset,type) "
     1966                      "SELECT :FILENAME, mark, data, type from "
     1967                      "recordedmarkup where chanid=:CHANID and starttime=:STARTTIME");
     1968
     1969        markup.bindValue(":FILENAME", copyToFile);
     1970        markup.bindValue(":CHANID", rec->chanid);
     1971        markup.bindValue(":STARTTIME", rec->recstartts);
     1972
     1973        if (!markup.exec() || !markup.isActive())
     1974        {
     1975            MythDB::DBError("video metadata update", markup);
     1976            return;
     1977        }
     1978
     1979        // Copy and set preview image as screenshot
     1980        // If Banners, cover files, or fanart exist with
     1981        // seriesID as the name, use them automatically.
     1982
     1983        QString screenshotFile = getPreviewImage(rec);
     1984        QString MVScreenshotDir = gContext->GetSetting("mythvideo.screenshotDir");
     1985        QString MVScreenshotFile = QString("%1/%2.png").arg(MVScreenshotDir).arg(MVFileFormat);
     1986
     1987        QString MVBannerDir = gContext->GetSetting("mythvideo.bannerDir");
     1988        QString bannerFile = testImageFiles(MVBannerDir, rec->seriesid, rec->title);
     1989        if (!bannerFile.isNull())
     1990            VERBOSE(VB_IMPORTANT, QString("Found Banner File Match: %1").arg(bannerFile));
     1991
     1992        QString MVFanartDir = gContext->GetSetting("mythvideo.fanartDir");
     1993        QString fanartFile = testImageFiles(MVFanartDir, rec->seriesid, rec->title);
     1994        if (!fanartFile.isNull())
     1995            VERBOSE(VB_IMPORTANT, QString("Found Fanart File Match: %1").arg(fanartFile));
     1996
     1997        QString MVCoverDir = gContext->GetSetting("VideoArtworkDir");
     1998        QString coverFile = testImageFiles(MVCoverDir, rec->seriesid, rec->title);
     1999        if (!coverFile.isNull())
     2000            VERBOSE(VB_IMPORTANT, QString("Found Cover File Match: %1").arg(coverFile));
     2001
     2002        VERBOSE(VB_IMPORTANT, QString("Copying %1 to %2").arg(screenshotFile).arg(MVScreenshotFile));
     2003
     2004        QFile fromScreenshot(screenshotFile);
     2005        QFile toScreenshot(MVScreenshotFile);
     2006        long long int screenshotBytesCopied;
     2007       
     2008        if (!screenshotFile.isNull())
     2009            screenshotBytesCopied = copy(toScreenshot,fromScreenshot);
     2010
     2011        if (!bannerFile.isNull() || !fanartFile.isNull()
     2012            || !coverFile.isNull() || !screenshotFile.isNull())
     2013        {
     2014            MSqlQuery images(MSqlQuery::InitCon());
     2015
     2016            images.prepare("UPDATE videometadata set screenshot=:SCREENSHOTFILE, "
     2017                           "banner=:BANNERFILE, fanart=:FANARTFILE, coverfile=:COVERFILE "
     2018                           "where filename=:FILENAME");
     2019
     2020            images.bindValue(":SCREENSHOTFILE", MVScreenshotFile);
     2021            images.bindValue(":BANNERFILE", bannerFile);
     2022            images.bindValue(":FANARTFILE", fanartFile);
     2023            images.bindValue(":COVERFILE", coverFile);
     2024            images.bindValue(":FILENAME", copyToFile);
     2025
     2026            if (!images.exec() || !images.isActive())
     2027            {
     2028                MythDB::DBError("video metadata update", images);
     2029                 return;
     2030            }
     2031        }
     2032        else
     2033        {
     2034            VERBOSE(VB_IMPORTANT, QString("Copy succeeded, but no images "
     2035                    "were copied or found."));
     2036            return;
     2037        }
     2038        VERBOSE(VB_IMPORTANT, QString("Copy succeeded, %1 bytes copied.").arg(bytesCopied));
     2039    }
     2040    else
     2041    {
     2042        VERBOSE(VB_IMPORTANT, QString("Copy unsuccessful, check all permissions."));
     2043    }
     2044
     2045    customExportDir.clear();
     2046    customExportFile.clear();
     2047    customExportSeason = 0;
     2048    customExportEpisode = 0;
     2049    seasonValue = 0;
     2050    episodeValue = 0;
     2051
     2052}
     2053
     2054unsigned int PlaybackBox::getLastSeason(QString title)
     2055{
     2056    unsigned int retSeason;
     2057
     2058    if (!title.isEmpty())
     2059    {
     2060        MSqlQuery season(MSqlQuery::InitCon());
     2061     
     2062        season.prepare("SELECT season from videometadata where "
     2063                     "title = :TITLE ORDER BY season DESC LIMIT 1");
     2064
     2065        season.bindValue(":TITLE", title);
     2066
     2067        if (season.exec() && season.next())
     2068        {
     2069            retSeason = season.value(0).toInt();
     2070        }
     2071        else
     2072            retSeason = 1;
     2073    }
     2074
     2075    return retSeason;
     2076}
     2077
     2078unsigned int PlaybackBox::getLastEpisode(QString title, unsigned int season)
     2079{       
     2080    unsigned int retEpisode;
     2081
     2082    if (!title.isEmpty())
     2083    {
     2084        MSqlQuery episode(MSqlQuery::InitCon());
     2085                 
     2086        episode.prepare("SELECT episode from videometadata where "
     2087                     "title = :TITLE AND season = :SEASON ORDER BY "
     2088                     "episode DESC LIMIT 1");
     2089           
     2090        episode.bindValue(":TITLE", title);
     2091        episode.bindValue(":SEASON", season);
     2092
     2093        if (episode.exec() && episode.next())
     2094        {
     2095            retEpisode = episode.value(0).toInt();
     2096        }
     2097        else
     2098            retEpisode = 0;
     2099    }
     2100
     2101    return retEpisode;
     2102}
     2103
     2104long int PlaybackBox::getLastInetref(QString title)
     2105{
     2106    long int retInetref;
     2107         
     2108    if (!title.isEmpty())   
     2109    {
     2110        MSqlQuery inetref(MSqlQuery::InitCon());
     2111           
     2112        inetref.prepare("SELECT inetref from videometadata where "
     2113                     "title = :TITLE ORDER BY inetref DESC LIMIT 1");
     2114           
     2115        inetref.bindValue(":TITLE", title);
     2116   
     2117        if (inetref.exec() && inetref.next())
     2118        {
     2119            retInetref = inetref.value(0).toInt();
     2120        }
     2121        else
     2122            retInetref = 0;
     2123    }   
     2124       
     2125    return retInetref;
     2126}
     2127
     2128QString PlaybackBox::replaceExportVariables(ProgramInfo *rec, QString &repString)
     2129{
     2130    if (!repString.isEmpty())
     2131    {
     2132        QString seasonOneDigit, seasonTwoDigit, episode;
     2133        episode = QString::number(episodeValue);
     2134       
     2135        if (episode.length() == 1)
     2136            episode.prepend("0");
     2137       
     2138        seasonOneDigit = seasonTwoDigit = QString::number(seasonValue);
     2139        if (seasonTwoDigit.length() == 1)
     2140            seasonTwoDigit.prepend("0");
     2141
     2142        repString.replace(QRegExp("%FILE%"), rec->GetRecordBasename(true));
     2143        repString.replace(QRegExp("%TITLE%"), rec->title);
     2144        repString.replace(QRegExp("%SUBTITLE%"), rec->subtitle);
     2145        repString.replace(QRegExp("%DESCRIPTION%"), rec->description);
     2146        repString.replace(QRegExp("%INETREF%"),
     2147                         QString::number(getLastInetref(rec->title)));
     2148        repString.replace(QRegExp("%HOSTNAME%"), rec->hostname);
     2149        repString.replace(QRegExp("%CATEGORY%"), rec->category);
     2150        repString.replace(QRegExp("%RECGROUP%"), rec->recgroup);
     2151        repString.replace(QRegExp("%PLAYGROUP%"), rec->playgroup);
     2152        repString.replace(QRegExp("%ORIGAIRYEAR%"),
     2153                         rec->originalAirDate.toString("yyyy"));
     2154        repString.replace(QRegExp("%ORIGAIRDATE%"),
     2155                         rec->originalAirDate.toString("yyyyMMdd"));
     2156        repString.replace(QRegExp("%CALLSIGN%"), rec->chansign);
     2157        repString.replace(QRegExp("%CHANNAME%"), rec->channame);
     2158        repString.replace(QRegExp("%CHANID%"), rec->chanid);
     2159        repString.replace(QRegExp("%STARTTIME%"),
     2160                         rec->recstartts.toString("yyyyMMddhhmmss"));
     2161        repString.replace(QRegExp("%ENDTIME%"),
     2162                         rec->recendts.toString("yyyyMMddhhmmss"));
     2163        repString.replace(QRegExp("%STARTTIMEISO%"),
     2164                         rec->recstartts.toString(Qt::ISODate));
     2165        repString.replace(QRegExp("%ENDTIMEISO%"),
     2166                         rec->recendts.toString(Qt::ISODate));
     2167        repString.replace(QRegExp("%PROGSTART%"),
     2168                         rec->startts.toString("yyyyMMddhhmmss"));
     2169        repString.replace(QRegExp("%PROGEND%"),
     2170                         rec->endts.toString("yyyyMMddhhmmss"));
     2171        repString.replace(QRegExp("%PROGSTARTISO%"),
     2172                         rec->startts.toString(Qt::ISODate));
     2173        repString.replace(QRegExp("%PROGENDISO%"),
     2174                         rec->endts.toString(Qt::ISODate));
     2175        if (seasonValue == 0 && episodeValue == 0)
     2176        {
     2177            // We don't want these to show up with movies. 
     2178            repString.replace(QRegExp("%SEASON%"), "");
     2179            repString.replace(QRegExp("%EPISODE%"), "");
     2180            repString.replace(QRegExp("%S##E##%"), "");
     2181            repString.replace(QRegExp("%##X##%"), "");
     2182            // This replace is just to remove extra junk
     2183            // from the filename if exporting a movie
     2184            // with the default export.
     2185            repString.replace(QRegExp("  - "), "");
     2186        }
     2187        else
     2188        {
     2189            repString.replace(QRegExp("%SEASON%"),
     2190                         QString::number(seasonValue));
     2191            repString.replace(QRegExp("%EPISODE%"),
     2192                         QString::number(episodeValue));
     2193            repString.replace(QRegExp("%S##E##%"),
     2194                         QString("s%1e%2").arg(seasonTwoDigit).arg(episode));
     2195            repString.replace(QRegExp("%##X##%"),   
     2196                         QString("%1x%2").arg(seasonOneDigit).arg(episode));
     2197        }
     2198    }
     2199    return repString;
     2200}
     2201
    18152202bool PlaybackBox::doRemove(ProgramInfo *rec, bool forgetHistory,
    18162203                           bool forceMetadataDelete)
    18172204{
     
    19262313                foundFile = *it;
    19272314                break;
    19282315            }
    1929         }
     2316        }   
    19302317        reg = regs[++regIndex];
    19312318    }
    19322319
    1933     return QString("%1/%2").arg(testDirectory).arg(foundFile);
    1934 }
     2320    if (!foundFile.isEmpty());
     2321        return QString("%1/%2").arg(testDirectory).arg(foundFile);
    19352322
     2323    return NULL;
     2324}   
     2325
    19362326void PlaybackBox::showActions(ProgramInfo *pginfo)
    19372327{
    19382328    if (!pginfo)
     
    19522342        showActionPopup(pginfo);
    19532343}
    19542344
     2345void PlaybackBox::showExportPopup(ProgramInfo *program)
     2346{
     2347    if (m_popupMenu)
     2348        return;
     2349
     2350    QString label = tr("Are you sure you want to export:");
     2351
     2352    m_expItem = CurrentItem();
     2353    popupString(m_expItem, label);
     2354
     2355    m_popupMenu = new MythDialogBox(label, m_popupStack, "pbbmainmenupopup");
     2356
     2357    connect(m_popupMenu, SIGNAL(Exiting()), SLOT(popupClosed()));
     2358
     2359    if (m_popupMenu->Create())
     2360        m_popupStack->AddScreen(m_popupMenu);
     2361    else
     2362    {
     2363        delete m_popupMenu;
     2364        m_popupMenu = NULL;
     2365    }
     2366
     2367    m_popupMenu->SetReturnEvent(this, "slotmenu");
     2368
     2369    m_freeSpaceNeedsUpdate = true;
     2370    QString tmpmessage;
     2371    const char *tmpslot = NULL;
     2372
     2373    if (program->IsSameProgram(*program))
     2374        {
     2375        tmpmessage = tr("Yes, Export to MythVideo");
     2376        tmpslot = SLOT(doMVExport());
     2377        m_popupMenu->AddButton(tmpmessage, tmpslot);
     2378
     2379        tmpmessage = tr("Export (Start New Season)");
     2380        tmpslot = SLOT(doNewSeasonExport());
     2381        m_popupMenu->AddButton(tmpmessage, tmpslot);
     2382
     2383        tmpmessage = tr("Export with custom name/location");
     2384        tmpslot = SLOT(showCustomExportEditor());
     2385        m_popupMenu->AddButton(tmpmessage, tmpslot);
     2386
     2387        tmpmessage = tr("No, I don't want to Export");
     2388        tmpslot = SLOT(noExport());
     2389        m_popupMenu->AddButton(tmpmessage, tmpslot);
     2390        }
     2391}
     2392
     2393
    19552394void PlaybackBox::doPIPPlay(void)
    19562395{
    19572396    doPIPPlay(kPIPonTV);
     
    23872826        else
    23882827            m_popupMenu->AddButton(tr("Preserve this episode"),
    23892828                                            SLOT(togglePreserveEpisode()));
     2829
     2830        QString MVlocation = FindPluginName("mythvideo");
     2831        if (QFile(MVlocation).exists())
     2832            m_popupMenu->AddButton(tr("Export to MythVideo"), SLOT(askMVExport()));
    23902833    }
    23912834}
    23922835
     
    26943137    stop(pginfo);
    26953138}
    26963139
     3140void PlaybackBox::doMVExport()
     3141{
     3142    ProgramInfo *pginfo = CurrentItem();
     3143    mvexport(pginfo);
     3144}
     3145
    26973146void PlaybackBox::showProgramDetails()
    26983147{
    26993148   ProgramInfo *pginfo = CurrentItem();
     
    28323281    }
    28333282}
    28343283
     3284void PlaybackBox::askMVExport(ProgramInfo *pginfo)
     3285{
     3286    if (!pginfo)
     3287        pginfo = CurrentItem();
     3288    showExportPopup(pginfo);
     3289}
     3290
    28353291void PlaybackBox::askDelete()
    28363292{
    28373293    if (m_delItem)
     
    40844540        m_recordingList->RemoveItem(item);
    40854541}
    40864542
     4543void PlaybackBox::showCustomExportEditor()
     4544{
     4545
     4546    MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
     4547
     4548    CustomExportEdit *editExport = new CustomExportEdit(mainStack);
     4549
     4550    if (editExport->Create())
     4551    {
     4552        connect(editExport, SIGNAL(result(const QString &, const QString &,
     4553                                        unsigned int, unsigned int)),
     4554                SLOT(startCustomExport(const QString &, const QString &,
     4555                                        unsigned int, unsigned int)));
     4556        mainStack->AddScreen(editExport);
     4557    }
     4558    else
     4559        delete editExport;
     4560}
     4561
     4562void PlaybackBox::doNewSeasonExport()
     4563{
     4564MythUIButtonListItem *item = m_recordingList->GetItemCurrent();
     4565
     4566    if (!item)
     4567        return;
     4568
     4569    ProgramInfo *pginfo = CurrentItem();
     4570
     4571    if (!pginfo)
     4572        return;
     4573
     4574    customExportFile = gContext->GetSetting("mythvideo.TVExportFileFormat",
     4575                              "%TITLE% %##X##% - %SUBTITLE%");
     4576    customExportDir = gContext->GetSetting("mythvideo.TVExportDirFormat",
     4577                              "Television/%TITLE%/");
     4578    customExportSeason = (getLastSeason(pginfo->title) + 1);
     4579    customExportEpisode = 1;
     4580
     4581    mvexport(pginfo);
     4582}
     4583
     4584void PlaybackBox::startCustomExport(const QString &newFile, const QString &newDir,
     4585                                    unsigned int newSeason, unsigned int newEpisode)
     4586{
     4587    MythUIButtonListItem *item = m_recordingList->GetItemCurrent();
     4588
     4589    if (!item)
     4590        return;
     4591
     4592    ProgramInfo *pginfo = CurrentItem();
     4593
     4594    if (!pginfo)
     4595        return;
     4596
     4597    customExportFile = newFile;
     4598    customExportDir = newDir;
     4599    customExportSeason = newSeason;
     4600    customExportEpisode = newEpisode;
     4601
     4602    mvexport(pginfo);
     4603}
     4604
    40874605void PlaybackBox::setRecGroup(QString newRecGroup)
    40884606{
    40894607    ProgramInfo *tmpItem = CurrentItem();
     
    44694987    Close();
    44704988}
    44714989
     4990////////////////////////////////////////////////////////
     4991
     4992CustomExportEdit::CustomExportEdit(MythScreenStack *lparent)
     4993                : MythScreenType(lparent, "customexportedit")
     4994{
     4995    m_dirEdit = m_fileEdit = NULL;
     4996}
     4997
     4998bool CustomExportEdit::Create()
     4999{
     5000    if (!LoadWindowFromXML("recordings-ui.xml", "customexport", this))
     5001        return false;
     5002       
     5003    m_dirEdit = dynamic_cast<MythUITextEdit*>(GetChild("dir"));
     5004    m_fileEdit = dynamic_cast<MythUITextEdit*>(GetChild("file"));
     5005    m_seasonSpin = dynamic_cast<MythUISpinBox *>(GetChild("season"));
     5006    m_episodeSpin = dynamic_cast<MythUISpinBox *>(GetChild("episode"));
     5007
     5008    MythUIButton *okButton = dynamic_cast<MythUIButton*>(GetChild("ok"));
     5009 
     5010    if (!m_dirEdit || !m_fileEdit || !m_seasonSpin ||
     5011                           !m_episodeSpin || !okButton)
     5012    {
     5013        VERBOSE(VB_IMPORTANT, "Window 'customexport' is missing required "
     5014                              "elements.");
     5015        return false;
     5016    }
     5017   
     5018    m_dirEdit->SetText(gContext->GetSetting("mythvideo.TVExportDirFormat"),
     5019                                 "Television/%TITLE%/");
     5020    m_fileEdit->SetText(gContext->GetSetting("mythvideo.TVExportFileFormat"),
     5021                                 "%TITLE% %##X##% - %SUBTITLE%");
     5022    m_seasonSpin->SetRange(0,100,1);
     5023    m_seasonSpin->SetValue(1);
     5024    m_episodeSpin->SetRange(0,999,1);
     5025    m_episodeSpin->SetValue(1);
     5026
     5027    connect(okButton, SIGNAL(Clicked()), SLOT(ReturnExport()));
     5028     
     5029    if (!BuildFocusList())
     5030        VERBOSE(VB_IMPORTANT, "Failed to build a focuslist.");
     5031 
     5032    return true;
     5033}
     5034
     5035void CustomExportEdit::ReturnExport()
     5036{
     5037    QString newExportDir = m_dirEdit->GetText();
     5038    QString newExportFile = m_fileEdit->GetText();
     5039    unsigned int newSeason = m_seasonSpin->GetIntValue();
     5040    unsigned int newEpisode = m_episodeSpin->GetIntValue();
     5041
     5042    emit result(newExportFile, newExportDir, newSeason, newEpisode);
     5043    Close();
     5044}
     5045
    44725046//////////////////////////////////////////
    44735047
    44745048HelpPopup::HelpPopup(MythScreenStack *lparent)
  • mythtv/programs/mythfrontend/playbackbox.h

     
    142142    void showRecGroupChanger();
    143143    void showPlayGroupChanger();
    144144    void showMetadataEditor();
     145    void showCustomExportEditor();
    145146    void showGroupFilter();
    146147    void showRecGroupPasswordChanger();
    147148    MythDialogBox *createPopupMenu(const QString &title);
     
    178179
    179180    void askStop();
    180181    void doStop();
     182    void askMVExport(ProgramInfo *pginfo = NULL);
     183    void doMVExport();
    181184
    182185    void doEditScheduled();
    183186    void doAllowRerecord();
     
    208211    void setPlayGroup(QString newPlayGroup);
    209212
    210213    void saveRecMetadata(const QString &newTitle, const QString &newSubtitle);
     214    void startCustomExport(const QString &newFile, const QString &newDir,
     215                           unsigned int newSeason, unsigned int newEpisode);
     216    void doNewSeasonExport();
    211217
    212218    void SetRecGroupPassword(const QString &newPasswd);
    213219
     
    254260
    255261    void checkPassword(const QString &password);
    256262
     263
    257264  protected:
    258265    bool SetPreviewGenerator(const QString &fn, PreviewGenerator *g);
    259266    void IncPreviewGeneratorPriority(const QString &fn);
     
    271278
    272279    bool play(ProgramInfo *rec, bool inPlaylist = false);
    273280    void stop(ProgramInfo *);
     281    void mvexport(ProgramInfo *);
     282    unsigned int getLastSeason(QString title);
     283    unsigned int getLastEpisode(QString title, unsigned int season);
     284    long int getLastInetref(QString title);
     285    QString replaceExportVariables(ProgramInfo *rec, QString &repString);
    274286    void remove(ProgramInfo *);
    275287    void showActions(ProgramInfo *);
    276288    ProgramInfo *CurrentItem(void);
     
    290302
    291303    bool doRemove(ProgramInfo *, bool forgetHistory, bool forceMetadataDelete);
    292304    void showDeletePopup(deletePopupType);
     305    void showExportPopup(ProgramInfo *);
    293306    void showActionPopup(ProgramInfo *program);
    294307    void showFileNotFoundActionPopup(ProgramInfo *program);
    295308    void popupString(ProgramInfo *program, QString &message);
     
    390403    // Other state
    391404    /// Program currently selected for deletion
    392405    ProgramInfo *m_delItem;
     406    /// Program currently selected for export
     407    ProgramInfo *m_expItem;
    393408    /// Program currently selected during an update
    394409    ProgramInfo *m_currentItem;
    395410    /// Group currently selected
     
    526541  private:
    527542    MythUITextEdit     *m_titleEdit;
    528543    MythUITextEdit     *m_subtitleEdit;
     544    MythUITextEdit     *m_descriptionEdit;
    529545
    530546    ProgramInfo *m_progInfo;
    531547};
    532548
     549class CustomExportEdit : public MythScreenType
     550{
     551    Q_OBJECT
     552
     553  public:
     554    CustomExportEdit(MythScreenStack *lparent);
     555
     556    bool Create(void);
     557
     558  signals:
     559    void result(const QString &, const QString &, unsigned int, unsigned int);
     560
     561  protected slots:   
     562    void ReturnExport(void);
     563 
     564  private:
     565    MythUITextEdit     *m_dirEdit;
     566    MythUITextEdit     *m_fileEdit;
     567    MythUISpinBox      *m_seasonSpin;
     568    MythUISpinBox      *m_episodeSpin;
     569
     570};
     571
    533572class HelpPopup : public MythScreenType
    534573{
    535574    Q_OBJECT