-added download of plugin covers via gametdb, currently only

works with extracted nintendo games (collection is very small
but will grow) as soon as more covers come you can also download
covers for other systems, also added a new option to plugin inis
for this day already, "consoleCoverID"
-updated english help file (thanks seam for info)
This commit is contained in:
fix94.1 2012-06-08 19:29:23 +00:00
parent 00419301c8
commit e28f9c3e72
7 changed files with 306 additions and 83 deletions

View File

@ -162,6 +162,7 @@ void CList<dir_discHdr>::GetHeaders(vector<string> pathlist, vector<dir_discHdr>
if(lowerCase(*itr).rfind((*type_itr).c_str()) != string::npos)
{
strncpy(tmp.path, (*itr).c_str(), sizeof(tmp.path));
strncpy((char*)tmp.hdr.id, "PLUGIN", sizeof(tmp.hdr.id));
int plugin_ccolor;
sscanf(plugin.getString("PLUGIN","coverColor","").c_str(), "%08x", &plugin_ccolor);

View File

@ -25,6 +25,8 @@
#define TAG_GAME_ID "{gameid}"
#define TAG_LOC "{loc}"
#define TAG_CONSOLE "{console}"
#define TITLES_URL "http://www.gametdb.com/titles.txt?LANG=%s"
#define GAMETDB_URL "http://www.gametdb.com/wiitdb.zip?LANG=%s&FALLBACK=TRUE&WIIWARE=TRUE&GAMECUBE=TRUE"
#define UPDATE_URL_VERSION "http://dl.dropbox.com/u/25620767/WiiflowMod/versions.txt"
@ -36,11 +38,11 @@
type *name = (type*)(((u32)(_al__##name)) + ((alignment) - (( \
(u32)(_al__##name))&((alignment)-1))))
static const char FMT_BPIC_URL[] = "http://art.gametdb.com/wii/coverfullHQ/{loc}/{gameid}.png"\
"|http://art.gametdb.com/wii/coverfull/{loc}/{gameid}.png";
static const char FMT_PIC_URL[] = "http://art.gametdb.com/wii/cover/{loc}/{gameid}.png";
static const char FMT_CBPIC_URL[] = "http://art.gametdb.com/wii/coverfullHQ2/{loc}/{gameid}.png";
static const char FMT_CPIC_URL[] = "http://art.gametdb.com/wii/cover2/{loc}/{gameid}.png";
static const char FMT_BPIC_URL[] = "http://art.gametdb.com/{console}/coverfullHQ/{loc}/{gameid}.png"\
"|http://art.gametdb.com/{console}/coverfull/{loc}/{gameid}.png";
static const char FMT_PIC_URL[] = "http://art.gametdb.com/{console}/cover/{loc}/{gameid}.png";
static const char FMT_CBPIC_URL[] = "http://art.gametdb.com/{console}/coverfullHQ2/{loc}/{gameid}.png";
static const char FMT_CPIC_URL[] = "http://art.gametdb.com/{console}/cover2/{loc}/{gameid}.png";
static block download = { 0, 0 };
static bool settingsmenu = false;
@ -129,9 +131,12 @@ static string countryCode(const string &gameId)
static string makeURL(const string format, const string gameId, const string country)
{
string url = format;
if (url.find(TAG_LOC) != url.npos)
url.replace(url.find(TAG_LOC), strlen(TAG_LOC), country.c_str());
if(url.find(TAG_LOC) != url.npos)
url.replace(url.find(TAG_LOC), strlen(TAG_LOC), country.c_str());
if(url.find(TAG_CONSOLE) != url.npos)
url.replace(url.find(TAG_LOC), strlen(TAG_LOC), "wii");
url.replace(url.find(TAG_GAME_ID), strlen(TAG_GAME_ID), gameId.c_str());
return url;
@ -454,13 +459,15 @@ int CMenu::_coverDownloader(bool missingOnly)
{
string path;
vector<string> coverList;
vector<dir_discHdr> pluginCoverList;
int count = 0, countFlat = 0;
float listWeight = missingOnly ? 0.125f : 0.f; // 1/8 of the progress bar for testing the PNGs we already have
float dlWeight = 1.f - listWeight;
u32 bufferSize = 0x280000; // Maximum download size 2 MB
SmartBuf buffer = smartAnyAlloc(bufferSize);
if (!buffer)
if(!buffer)
{
LWP_MutexLock(m_mutex);
_setThrdMsg(L"Not enough memory!", 1.f);
@ -495,10 +502,28 @@ int CMenu::_coverDownloader(bool missingOnly)
_setThrdMsg(_t("dlmsg7", L"Listing covers to download..."), listWeight * (float)step / (float)nbSteps);
LWP_MutexUnlock(m_mutex);
++step;
string id((const char *)m_gameList[i].hdr.id, sizeof m_gameList[i].hdr.id);
path = sfmt("%s/%s.png", m_boxPicDir.c_str(), id.c_str());
string id;
if(m_current_view == COVERFLOW_EMU)
{
char gamePath[256];
if(string(m_gameList[i].path).find_last_of("/") != string::npos)
strncpy(gamePath, &m_gameList[i].path[string(m_gameList[i].path).find_last_of("/")], sizeof(gamePath));
else
strncpy(gamePath, m_gameList[i].path, sizeof(gamePath));
path = sfmt("%s/%s.png", m_boxPicDir.c_str(), gamePath);
id = path;
}
else
{
id = (const char *)m_gameList[i].hdr.id;
path = sfmt("%s/%s.png", m_boxPicDir.c_str(), id.c_str());
}
if (!missingOnly || (!m_cf.fullCoverCached(id.c_str()) && !checkPNGFile(path.c_str())))
{
if(m_current_view == COVERFLOW_EMU)
pluginCoverList.push_back(m_gameList[i]);
coverList.push_back(id);
}
}
}
else
@ -578,8 +603,11 @@ int CMenu::_coverDownloader(bool missingOnly)
if (!checkPNGFile(path.c_str()))
{
for (u32 j = 0; !success && j < fmtURLBox.size() && !m_thrdStop; ++j)
{
url = makeURL(fmtURLBox[j], newID, countryCode(newID));
{
if(m_current_view == COVERFLOW_EMU)
url = m_plugin.GenerateCoverLink(pluginCoverList[i], fmtURLBox[j]);
else
url = makeURL(fmtURLBox[j], newID, countryCode(newID));
if (j == 0) ++step;
m_thrdStep = listWeight + dlWeight * (float)step / (float)nbSteps;
LWP_MutexLock(m_mutex);
@ -592,9 +620,11 @@ int CMenu::_coverDownloader(bool missingOnly)
bool tdl = false;
if(download.data != NULL && download.size > 0 && checkPNGBuf(download.data))
break;
if(m_current_view == COVERFLOW_EMU)
break;
switch( o )
{
case EN:
case EN:
if(( newID[3] == 'E' || newID[3] == 'X' || newID[3] == 'Y' || newID[3] == 'P') && m_downloadPrioVal&C_TYPE_EN )
url = makeURL(fmtURLBox[j], newID, "EN");
tdl = true;
@ -685,12 +715,12 @@ int CMenu::_coverDownloader(bool missingOnly)
continue;
if (savePNG)
{
{
LWP_MutexLock(m_mutex);
_setThrdMsg(wfmt(_fmt("dlmsg4", L"Saving %s"), path.c_str()), listWeight + dlWeight * (float)(step + 1) / (float)nbSteps);
LWP_MutexUnlock(m_mutex);
file = fopen(path.c_str(), "wb");
if (file != NULL)
if(file != NULL)
{
fwrite(download.data, download.size, 1, file);
fclose(file);
@ -714,13 +744,16 @@ int CMenu::_coverDownloader(bool missingOnly)
custom = true;
c_altCase = c_gameTDB.GetCaseVersions( coverList[i].c_str() );
if (!success && !m_thrdStop && c_gameTDB.IsLoaded() && c_altCase > 1 && custom)
{
{
path = sfmt("%s/%s.png", m_boxPicDir.c_str(), coverList[i].c_str());
if (!checkPNGFile(path.c_str()))
{
for (u32 j = 0; !success && j < fmtURLCBox.size() && !m_thrdStop; ++j)
{
url = makeURL(fmtURLCBox[j], newID, countryCode(newID));
{
if(m_current_view == COVERFLOW_EMU)
url = m_plugin.GenerateCoverLink(pluginCoverList[i], fmtURLCBox[j]);
else
url = makeURL(fmtURLCBox[j], newID, countryCode(newID));
if (j == 0) ++step;
m_thrdStep = listWeight + dlWeight * (float)step / (float)nbSteps;
LWP_MutexLock(m_mutex);
@ -731,11 +764,12 @@ int CMenu::_coverDownloader(bool missingOnly)
{
bool tdl = false;
if(download.data != NULL && download.size > 0 && checkPNGBuf(download.data))
break;
break;
if(m_current_view == COVERFLOW_EMU)
break;
switch( o )
{
case EN:
case EN:
if(( newID[3] == 'E' || newID[3] == 'X' || newID[3] == 'Y' || newID[3] == 'P') && m_downloadPrioVal&C_TYPE_EN )
{
url = makeURL(fmtURLCBox[j], newID, "EN");
@ -853,7 +887,7 @@ int CMenu::_coverDownloader(bool missingOnly)
}
}
break;
case FLAT:
case FLAT:
if( m_downloadPrioVal&C_TYPE_ONOR )
original = false;
if (!success && !m_thrdStop && original)
@ -865,7 +899,10 @@ int CMenu::_coverDownloader(bool missingOnly)
if (m_thrdStop) break;
for (u32 j = 0; !success && j < fmtURLFlat.size() && !m_thrdStop; ++j)
{
url = makeURL(fmtURLFlat[j], newID, countryCode(newID));
if(m_current_view == COVERFLOW_EMU)
url = m_plugin.GenerateCoverLink(pluginCoverList[i], fmtURLFlat[j]);
else
url = makeURL(fmtURLFlat[j], newID, countryCode(newID));
LWP_MutexLock(m_mutex);
_setThrdMsg(wfmt(_fmt("dlmsg8", L"Full cover not found. Downloading from %s"), url.c_str()), listWeight + dlWeight * (float)step / (float)nbSteps);
LWP_MutexUnlock(m_mutex);
@ -875,11 +912,12 @@ int CMenu::_coverDownloader(bool missingOnly)
{
bool tdl = false;
if(download.data != NULL && download.size > 0 && checkPNGBuf(download.data))
break;
break;
if(m_current_view == COVERFLOW_EMU)
break;
switch( o )
{
case EN:
case EN:
if(( newID[3] == 'E' || newID[3] == 'X' || newID[3] == 'Y' || newID[3] == 'P') && m_downloadPrioVal&C_TYPE_EN )
{
url = makeURL(fmtURLFlat[j], newID, "EN");
@ -1157,6 +1195,7 @@ int CMenu::_coverDownloader(bool missingOnly)
_setThrdMsg(wfmt(_fmt("dlmsg9", L"%i/%i files downloaded. %i are front covers only."), count + countFlat, n, countFlat), 1.f);
LWP_MutexUnlock(m_mutex);
m_thrdWorking = false;
pluginCoverList.clear();
buffer.release();
return 0;
}
@ -1174,8 +1213,20 @@ void CMenu::_download(string gameId)
m_btnMgr.setText(m_downloadBtnCancel, _t("dl1", L"Cancel"));
m_thrdStop = false;
m_thrdMessageAdded = false;
m_coverDLGameId = gameId;
while (true)
if((m_current_view == COVERFLOW_EMU) && gameId.size())
{
char gamePath[256];
if(string(m_cf.getHdr()->path).find_last_of("/") != string::npos)
strncpy(gamePath, &m_cf.getHdr()->path[string(m_cf.getHdr()->path).find_last_of("/")], sizeof(gamePath));
else
strncpy(gamePath, m_cf.getHdr()->path, sizeof(gamePath));
m_coverDLGameId = gamePath;
}
else
m_coverDLGameId = gameId;
while(true)
{
_mainLoopCommon(false, m_thrdWorking);
if ((BTN_HOME_PRESSED || BTN_B_PRESSED) && !m_thrdWorking)

127
source/plugin/crc32.c Normal file
View File

@ -0,0 +1,127 @@
/* Copyright (C) 1986 Gary S. Brown. You may use this program, or
code or tables extracted from it, as desired without restriction.*/
/* First, the polynomial itself and its table of feedback terms. The */
/* polynomial is */
/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
/* Note that we take it "backwards" and put the highest-order term in */
/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */
/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */
/* the MSB being 1. */
/* Note that the usual hardware shift register implementation, which */
/* is what we're using (we're merely optimizing it by doing eight-bit */
/* chunks at a time) shifts bits into the lowest-order term. In our */
/* implementation, that means shifting towards the right. Why do we */
/* do it this way? Because the calculated CRC must be transmitted in */
/* order from highest-order term to lowest-order term. UARTs transmit */
/* characters in order from LSB to MSB. By storing the CRC this way, */
/* we hand it to the UART in the order low-byte to high-byte; the UART */
/* sends each low-bit to hight-bit; and the result is transmission bit */
/* by bit from highest- to lowest-order term without requiring any bit */
/* shuffling on our part. Reception works similarly. */
/* The feedback terms table consists of 256, 32-bit entries. Notes: */
/* */
/* 1. The table can be generated at runtime if desired; code to do so */
/* is shown later. It might not be obvious, but the feedback */
/* terms simply represent the results of eight shift/xor opera- */
/* tions for all combinations of data and CRC register values. */
/* */
/* 2. The CRC accumulation logic is the same for all CRC polynomials, */
/* be they sixteen or thirty-two bits wide. You simply choose the */
/* appropriate table. Alternatively, because the table can be */
/* generated at runtime, you can start by generating the table for */
/* the polynomial in question and use exactly the same "updcrc", */
/* if your application needn't simultaneously handle two CRC */
/* polynomials. (Note, however, that XMODEM is strange.) */
/* */
/* 3. For 16-bit CRCs, the table entries need be only 16 bits wide; */
/* of course, 32-bit entries work OK if the high 16 bits are zero. */
/* */
/* 4. The values must be right-shifted by eight bits by the "updcrc" */
/* logic; the shift must be unsigned (bring in zeroes). On some */
/* hardware you could probably optimize the shift in assembler by */
/* using byte-swap instructions. */
#include <stdio.h>
#include <ogc/system.h>
#include "crc32.h"
static u32 crc_32_tab[] = { /* CRC polynomial 0xedb88320 */
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
u32 crc32file(char *name)
{
FILE *fin;
s32 c;
u32 oldcrc32 = 0xFFFFFFFF;
s32 charcnt = 0;
if((fin = fopen(name, "rb")) == NULL)
{
perror(name);
return oldcrc32;
}
while((c = getc(fin)) != EOF)
{
++charcnt;
oldcrc32 = UPDC32(c, oldcrc32);
}
if(ferror(fin))
{
perror(name);
charcnt = -1;
}
fclose(fin);
u32 crc32 = oldcrc32 = ~oldcrc32;
return crc32;
}

18
source/plugin/crc32.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef CRC32_H
#define CRC32_H
#ifdef __cplusplus
extern "C"
{
#endif
#define UPDC32(octet, crc) (crc_32_tab[((crc)\
^ (octet)) & 0xff] ^ ((crc) >> 8))
u32 crc32file(char *name);
#ifdef __cplusplus
}
#endif
#endif /* CRC32_H */

View File

@ -15,12 +15,17 @@
#include "devicemounter/PartitionHandle.h"
#include "devicemounter/DeviceHandler.hpp"
#include "defines.h"
#include "crc32.h"
static const string emptyString;
static const string emptyString2("/");
static char* emptyChar = (char*)" ";
u32 ScummVM_magic;
#define TAG_GAME_ID "{gameid}"
#define TAG_LOC "{loc}"
#define TAG_CONSOLE "{console}"
void Plugin::init(string m_pluginsDir)
{
ScummVM_magic = 0;
@ -62,6 +67,7 @@ bool Plugin::AddPlugin(Config &plugin)
PluginName.erase(PluginName.end() - 4, PluginName.end());
}
NewPlugin.DisplayName.fromUTF8(PluginName.c_str());
NewPlugin.consoleCoverID = plugin.getString("PLUGIN","consoleCoverID","");
string bannerfilepath = sfmt("%s/%s", pluginsDir.c_str(), plugin.getString("PLUGIN","bannerSound","").c_str());
ifstream infile;
@ -274,3 +280,20 @@ bool Plugin::isScummVM(u32 magic)
{
return (magic == ScummVM_magic);
}
string Plugin::GenerateCoverLink(dir_discHdr gameHeader, string url)
{
Plugin_Pos = GetPluginPosition(gameHeader.hdr.magic);
if(url.find(TAG_LOC) != url.npos)
url.replace(url.find(TAG_LOC), strlen(TAG_LOC), "EN");
if(url.find(TAG_CONSOLE) != url.npos)
url.replace(url.find(TAG_CONSOLE), strlen(TAG_CONSOLE), (Plugins[Plugin_Pos].consoleCoverID.size() ? Plugins[Plugin_Pos].consoleCoverID.c_str() : "nintendo"));
char crc_string[9];
snprintf(crc_string, sizeof(crc_string), "%08x", crc32file(gameHeader.path));
url.replace(url.find(TAG_GAME_ID), strlen(TAG_GAME_ID), upperCase(crc_string).c_str());
gprintf("URL: %s\n", url.c_str());
return url;
}

View File

@ -24,6 +24,7 @@ struct PluginOptions
u32 magicWord;
string DolName;
string coverFolder;
string consoleCoverID;
wstringEx DisplayName;
u32 caseColor;
bool ReturnLoader;
@ -37,6 +38,7 @@ public:
u32 GetBannerSoundSize();
char* GetDolName(u32 magic);
char* GetCoverFolderName(u32 magic);
string GenerateCoverLink(dir_discHdr gameHeader, string url);
wstringEx GetPluginName(u8 pos);
u32 getPluginMagic(u8 pos);
bool PluginExist(u8 pos);

View File

@ -1,54 +1,55 @@
Controls:
- Main menu (coverflow) :
-- Up / Down = Previous / next game (vertical)
-- Left / Right = Previous / next game (horizontal)
-- Minus / Plus = Fast skip through games
-- A = Select game
-- B+A = Launch game immediately
-- B+Home = Reload Wiiflow
-- Home = Exit to Wii menu
-- 1 / 2 = Previous / next coverflow mode
-- B+Left / B+Right = Change Song
-- B+UP / B+DOWN = Alphabetic search
-- B+Onscreen Arrows = Alphabetic search
-- B+Minus = Switch Partition
-- B+Plus = Sort Games
-- A on Star Icon = Favorites
-- B on Star Icon = Categories
-- A on Gear Icon = Wiiflow settings
-- A on Disc Icon (Game Disc in Drive) = Launch game disc
-- A on USB Icon = Switch to Game menu (icon changes to channels)
-- A on Channels Icon = Switch to Channels menu (icon changes to USB)
-- A on Home Icon = Exit to Wii Menu
- Game :
-- A on box = Show the backside
-- A out of screen = Launch game
-- B = Back to coverflow
-- Up / Down = Previous / next game (vertical)
-- Left / Right = Previous / next game (horizontal)
-- Plus = Game Info
---Right (in Game Info) = Game Description
---Left (in Game Desc) = Game Info
-- A on Star Icon = Toggle Favorite (Yellow = Favorite)
-- A on Hand Icon = Parental Lock (Red = locked)
-- A on Gear Icon = Game Settings
-- A on X Icon = Delete Game
- Settings menus :
-- Minus / Plus = Previous / next page
-- Left / Right = Previous / next page
- Coverflow Adjust settings :
-- B+Minus / B+Plus = Previous / next page
-- B = Faster adjustment (B+A instead of just A to click a button)
-- B+1 = Copy whole coverflow
-- B+2 = Paste coverflow\n\
TIPS for running games that crash:
If the game just locks up with a black screen at launch then check to see if it is a PAL game.
(Press the Plus button on the game screen.) If it is PAL, then set the game's video mode to "PAL 50Hz" in the game's setting screen.
You will need to use a component connection to the TV and have your WII set to 480p video mode.
If a game crashes, then try running the game again. If it continually crashes, then turn the USB Emulation to \"Off\" in the game's setting screen.

Controls:
- Main menu (coverflow) :
-- Up / Down = Previous / next game (vertical)
-- Left / Right = Previous / next game (horizontal)
-- Minus / Plus = Fast skip through games
-- A = Select game
-- B+A = Launch game immediately
-- B+Home = Reload Wiiflow
-- Home = Exit to Wii menu
-- 1 / 2 = Previous / next coverflow mode
-- B+Left / B+Right = Change Song
-- B+UP / B+DOWN = Alphabetic search
-- B+Onscreen Arrows = Alphabetic search
-- B+Minus = Switch Partition
-- B+Plus = Sort Games
-- A on Star Icon = Favorites
-- B on Star Icon = Categories
-- A on Gear Icon = Wiiflow settings
-- A on Disc Icon (Game Disc in Drive) = Launch game disc
-- A on USB Icon = Switch to Game menu (icon changes to channels)
-- A on Channels Icon = Switch to Channels menu (icon changes to USB)
-- A on Home Icon = Display source menu
- Game :
-- A on box = Show the backside
-- A out of screen = Launch game
-- B = Back to coverflow
-- Up / Down = Previous / next game (vertical)
-- Left / Right = Previous / next game (horizontal)
-- Plus = Game Info
---Right (in Game Info) = Game Description
---Left (in Game Desc) = Game Info
-- A on Star Icon = Toggle Favorite (Yellow = Favorite)
-- A on Hand Icon = Parental Lock (Red = locked)
-- A on Gear Icon = Game Settings
-- A on X Icon = Delete Game
- Settings menus :
-- Minus / Plus = Previous / next page
-- Left / Right = Previous / next page
- Coverflow Adjust settings :
-- B+Minus / B+Plus = Previous / next page
-- B = Faster adjustment (B+A instead of just A to click a button)
-- B+1 = Copy whole coverflow
-- B+2 = Paste coverflow\n\
TIPS for running games that crash:
If the game just locks up with a black screen at launch then check to see if it is a PAL game.
(Press the Plus button on the game screen.) If it is PAL, then set the game's video mode to "PAL 50Hz" in the game's setting screen.
You will need to use a component connection to the TV and have your WII set to 480p video mode.
If a game crashes, then try running the game again. If it continually crashes, then turn the USB Emulation to \"Off\" in the game's setting screen.