std::wstring ConvertRfc822ToLocal(const std::wstring& datetime) { auto time = ConvertRfc822(datetime); std::tm local_tm = {0}; if (localtime_s(&local_tm, &time) != 0) return datetime; std::string result(100, '\0'); std::strftime(&result.at(0), result.size(), "%a, %d %b %Y %H:%M:%S", &local_tm); TIME_ZONE_INFORMATION time_zone_info = {0}; const auto time_zone_id = GetTimeZoneInformation(&time_zone_info); const auto bias = time_zone_info.Bias + time_zone_info.DaylightBias; std::wstring sign = bias <= 0 ? L"+" : L"-"; int hh = std::abs(bias) / 60; int mm = std::abs(bias) % 60; std::wstring result_with_tz = StrToWstr(result) + L" " + sign + PadChar(ToWstr(hh), L'0', 2) + PadChar(ToWstr(mm), L'0', 2); return result_with_tz; }
SemanticVersion::operator string_t() const { string_t version = ToWstr(static_cast<int>(major)) + L"." + ToWstr(static_cast<int>(minor)) + L"." + ToWstr(static_cast<int>(patch)); if (!prerelease_identifiers.empty()) version += L"-" + prerelease_identifiers; if (!build_metadata.empty()) version += L"+" + build_metadata; return version; }
std::wstring Url::Build() const { std::wstring url; switch (protocol) { case base::http::kHttp: default: url += L"http"; break; case base::http::kHttps: url += L"https"; break; } url += L"://"; url += host; if (port > 0) url += L":" + ToWstr(port); url += path; if (!query.empty()) { std::wstring query_string; foreach_(it, query) { query_string += query_string.empty() ? L"?" : L"&"; query_string += it->first + L"=" + EncodeUrl(it->second, false); }
void FolderMonitor::OnFile(const DirectoryChangeNotification& notification) const { anime::Episode episode; auto anime_item = FindAnimeItem(notification, episode); if (!anime_item) return; if (!Meow.IsValidAnimeType(episode) || !Meow.IsValidFileExtension(episode)) return; bool path_available = notification.action != FILE_ACTION_REMOVED; // Set anime folder if (path_available && anime_item->GetFolder().empty()) { ChangeAnimeFolder(*anime_item, episode.folder); } // Set episode availability int lower_bound = anime::GetEpisodeLow(episode); int upper_bound = anime::GetEpisodeHigh(episode); std::wstring path = notification.path + notification.filename.first; for (int number = lower_bound; number <= upper_bound; ++number) { if (anime_item->SetEpisodeAvailability(number, path_available, path)) { LOG(LevelDebug, anime_item->GetTitle() + L" #" + ToWstr(number) + L" is " + (path_available ? L"available." : L"unavailable.")); } } }
INT_PTR StatsDialog::DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { ResizeProc(hwnd, uMsg, wParam, lParam); switch (uMsg) { case WM_CTLCOLORSTATIC: { win::Dc dc = reinterpret_cast<HDC>(wParam); dc.SetBkMode(TRANSPARENT); dc.DetachDc(); return reinterpret_cast<INT_PTR>(::GetSysColorBrush(COLOR_WINDOW)); } case WM_DRAWITEM: { // Draw score bars if (wParam == IDC_STATIC_ANIME_STAT2) { LPDRAWITEMSTRUCT dis = reinterpret_cast<LPDRAWITEMSTRUCT>(lParam); win::Rect rect = dis->rcItem; win::Dc dc = dis->hDC; dc.FillRect(dis->rcItem, ::GetSysColor(COLOR_WINDOW)); int bar_height = GetTextHeight(dc.Get()); int bar_max = rect.Width() * 3 / 4; for (int i = 10; i > 0; i--) { if (i < 10) rect.top += bar_height; if (Stats.score_distribution[i] > 0.0f) { int bar_width = static_cast<int>(bar_max * Stats.score_distribution[i]); rect.bottom = rect.top + bar_height - 2; rect.right = rect.left + bar_width; dc.FillRect(rect, ui::kColorDarkBlue); } if (Stats.score_count[i] > 0.0f) { std::wstring text = ToWstr(Stats.score_count[i]); win::Rect rect_text = rect; rect_text.left = rect_text.right += 8; rect_text.right = dis->rcItem.right; dc.EditFont(nullptr, 7); dc.SetBkMode(TRANSPARENT); dc.SetTextColor(::GetSysColor(COLOR_GRAYTEXT)); dc.DrawText(text.c_str(), text.length(), rect_text, DT_SINGLELINE | DT_VCENTER); } } dc.DetachDc(); return TRUE; } break; } case WM_ERASEBKGND: return TRUE; } return DialogProcDefault(hwnd, uMsg, wParam, lParam); }
void AnimeDialog::Refresh(bool image, bool series_info, bool my_info, bool connect) { if (!IsWindow()) return; auto anime_item = AnimeDatabase.FindItem(anime_id_); // Load image if (image) { ImageDatabase.Load(anime_id_, true, connect); win32::Rect rect; GetClientRect(&rect); SIZE size = {rect.Width(), rect.Height()}; OnSize(WM_SIZE, 0, size); RedrawWindow(); } // Set title if (anime_item) { if (Settings.Program.List.english_titles) { SetDlgItemText(IDC_EDIT_ANIME_TITLE, anime_item->GetEnglishTitle(true).c_str()); } else { SetDlgItemText(IDC_EDIT_ANIME_TITLE, anime_item->GetTitle().c_str()); } } else if (anime_id_ == anime::ID_NOTINLIST) { SetDlgItemText(IDC_EDIT_ANIME_TITLE, CurrentEpisode.title.c_str()); } else { SetDlgItemText(IDC_EDIT_ANIME_TITLE, L"Now Playing"); } // Set content if (anime_id_ == anime::ID_NOTINLIST) { wstring content = L"Taiga was unable to recognize this title, and needs your help.\n\n"; auto scores = Meow.GetScores(); if (!scores.empty()) { int count = 0; content += L"Please choose the correct one from the list below:\n\n"; foreach_c_(it, scores) { content += L" \u2022 <a href=\"score\" id=\"" + ToWstr(it->second) + L"\">" + AnimeDatabase.items[it->second].GetTitle() + L"</a>" #ifdef _DEBUG L" [Score: " + ToWstr(it->first) + L"]" #endif L"\n"; if (++count >= 10) break; }
bool AppSettings::Save() { xml_document document; xml_node settings = document.append_child(L"settings"); // Meta Set(kMeta_Version_Major, ToWstr(Taiga.version.major)); Set(kMeta_Version_Minor, ToWstr(Taiga.version.minor)); Set(kMeta_Version_Revision, ToWstr(Taiga.version.patch)); for (enum_t i = kAppSettingNameFirst; i < kAppSettingNameLast; ++i) WriteValue(settings, i); // Library folders xml_node folders = settings.child(L"anime").child(L"folders"); foreach_(it, library_folders) { xml_node root = folders.append_child(L"root"); root.append_attribute(L"folder") = it->c_str(); }
std::wstring ToSizeString(QWORD qwSize) { std::wstring size, unit; if (qwSize > 1073741824) { // 2^30 size = ToWstr(static_cast<double>(qwSize) / 1073741824, 2); unit = L" GB"; } else if (qwSize > 1048576) { // 2^20 size = ToWstr(static_cast<double>(qwSize) / 1048576, 2); unit = L" MB"; } else if (qwSize > 1024) { // 2^10 size = ToWstr(static_cast<double>(qwSize) / 1024, 2); unit = L" KB"; } else { size = ToWstr(qwSize); unit = L" bytes"; } return size + unit; }
int TranslateSeriesStatusFrom(int value) { switch (value) { case kCurrentlyAiring: return anime::kAiring; case kFinishedAiring: return anime::kFinishedAiring; case kNotYetAired: return anime::kNotYetAired; } LOG(LevelWarning, L"Unknown value: " + ToWstr(value)); return anime::kUnknownStatus; }
int AskForConfirmation(anime::Episode& episode) { auto anime_item = AnimeDatabase.FindItem(episode.anime_id); // Set up dialog win32::TaskDialog dlg; wstring title = L"Anime title: " + anime_item->GetTitle(); dlg.SetWindowTitle(APP_TITLE); dlg.SetMainIcon(TD_ICON_INFORMATION); dlg.SetMainInstruction(L"Do you want to update your anime list?"); dlg.SetContent(title.c_str()); dlg.SetVerificationText(L"Don't ask again, update automatically"); dlg.UseCommandLinks(true); // Get episode number int number = GetEpisodeHigh(episode.number); if (number == 0) number = 1; if (anime_item->GetEpisodeCount() == 1) episode.number = L"1"; // Add buttons if (anime_item->GetMyStatus() != mal::MYSTATUS_NOTINLIST) { if (anime_item->GetEpisodeCount() == number) { // Completed dlg.AddButton(L"Update and move\n" L"Update and set as completed", IDCANCEL); } else if (anime_item->GetMyStatus() != mal::MYSTATUS_WATCHING) { // Watching dlg.AddButton(L"Update and move\n" L"Update and set as watching", IDCANCEL); } } wstring button = L"Update\n" L"Update episode number from " + ToWstr(anime_item->GetMyLastWatchedEpisode()) + L" to " + ToWstr(number); dlg.AddButton(button.c_str(), IDYES); dlg.AddButton(L"Cancel\n" L"Don't update anything", IDNO); // Show dialog dlg.Show(g_hMain); if (dlg.GetVerificationCheck()) Settings.Account.Update.ask_to_confirm = FALSE; return dlg.GetSelectedButtonID(); }
void Tester::End(std::wstring str, bool display_result) { LARGE_INTEGER li; ::QueryPerformanceCounter(&li); double value = double(li.QuadPart - value_) / frequency_; if (display_result) { str = ToWstr(value, 2) + L"ms | Text: [" + str + L"]"; ui::DlgMain.SetText(str); } }
void Service::SearchTitle(Response& response, HttpResponse& http_response) { Json::Value root; if (!ParseResponseBody(response, http_response, root)) return; for (size_t i = 0; i < root.size(); i++) { ::anime::Item anime_item; anime_item.SetSource(this->id()); anime_item.SetId(ToWstr(root[i]["id"].asInt()), this->id()); anime_item.SetLastModified(time(nullptr)); // current time ParseAnimeObject(root[i], anime_item); int anime_id = AnimeDatabase.UpdateItem(anime_item); // We return a list of IDs so that we can display the results afterwards AppendString(response.data[L"ids"], ToWstr(anime_id), L","); } }
std::wstring GetRelativeTimeString(time_t unix_time) { if (!unix_time) return L"Unknown"; std::tm tm; if (localtime_s(&tm, &unix_time)) { return L"Unknown"; } std::wstring str; auto date_now = GetDate(); auto str_time = [](std::tm& tm, const char* format) { std::string result(100, '\0'); std::strftime(&result.at(0), result.size(), format, &tm); return StrToWstr(result); }; if (1900 + tm.tm_year < date_now.year) { str = Date(1900 + tm.tm_year, tm.tm_mon + 1, tm.tm_mday); // YYYY-MM-DD } else if (tm.tm_mon + 1 < date_now.month) { str = str_time(tm, "%B %d"); // January 1 } else { time_t seconds = time(nullptr) - unix_time; if (seconds >= 60 * 60 * 24) { auto value = std::lround(static_cast<float>(seconds) / (60 * 60 * 24)); str = ToWstr(value) + (value == 1 ? L" day" : L" days"); } else if (seconds >= 60 * 60) { auto value = std::lround(static_cast<float>(seconds) / (60 * 60)); str = ToWstr(value) + (value == 1 ? L" hour" : L" hours"); } else if (seconds >= 60) { auto value = std::lround(static_cast<float>(seconds) / 60); str = ToWstr(value) + (value == 1 ? L" minute" : L" minutes"); } else { str = L"a moment"; } str += L" ago"; } return str; }
bool Engine::ValidateEpisodeNumber(anime::Episode& episode, const anime::Item& anime_item, const MatchOptions& match_options, bool redirect) const { if (episode.elements().empty(anitomy::kElementEpisodeNumber)) { if (anime_item.GetEpisodeCount() == 1) return true; // Single-episode anime can do without an episode number if (episode.file_extension().empty()) return true; // It's a batch release } auto range = episode.episode_number_range(); if (range.second > 0 && // We need this to be able to redirect episode 0 range.second <= anime_item.GetEpisodeCount()) { return true; // Episode number is within range } if (match_options.allow_sequels) { int destination_id = anime::ID_UNKNOWN; std::pair<int, int> destination_range; if (SearchEpisodeRedirection(anime_item.GetId(), range, destination_id, destination_range)) { if (redirect) { LOG(LevelDebug, L"Redirection: " + ToWstr(anime_item.GetId()) + L":" + anime::GetEpisodeRange(episode) + L" -> " + ToWstr(destination_id) + L":" + anime::GetEpisodeRange(destination_range)); episode.anime_id = destination_id; episode.set_episode_number_range(destination_range); } return true; // Redirection available } } if (!anime::IsValidEpisodeCount(anime_item.GetEpisodeCount())) return true; // Episode count is unknown, so anything goes return false; // Episode number is out of range }
std::wstring TranslateMyStatusTo(int value) { switch (value) { case anime::kWatching: return L"currently-watching"; case anime::kCompleted: return L"completed"; case anime::kOnHold: return L"on-hold"; case anime::kDropped: return L"dropped"; case anime::kPlanToWatch: return L"plan-to-watch"; } LOG(LevelWarning, L"Unknown value: " + ToWstr(value)); return L""; }
int TranslateSeriesTypeFrom(int value) { switch (value) { case kTv: return anime::kTv; case kOva: return anime::kOva; case kMovie: return anime::kMovie; case kSpecial: return anime::kSpecial; case kOna: return anime::kOna; case kMusic: return anime::kMusic; } LOG(LevelWarning, L"Unknown value: " + ToWstr(value)); return anime::kUnknownType; }
void StatsDialog::Refresh() { if (!IsWindow()) return; // Anime list std::wstring text; text += ToWstr(Stats.anime_count) + L"\n"; text += ToWstr(Stats.episode_count) + L"\n"; text += Stats.life_spent_watching + L"\n"; text += ToWstr(Stats.score_mean, 2) + L"\n"; text += ToWstr(Stats.score_deviation, 2); SetDlgItemText(IDC_STATIC_ANIME_STAT1, text.c_str()); // Score distribution win::Window window = GetDlgItem(IDC_STATIC_ANIME_STAT2); win::Rect rect; window.GetWindowRect(GetWindowHandle(), &rect); InvalidateRect(&rect); window.SetWindowHandle(nullptr); // Database text.clear(); text += ToWstr(AnimeDatabase.items.size()) + L"\n"; text += ToWstr(Stats.image_count) + L" (" + ToSizeString(Stats.image_size) + L")\n"; text += ToWstr(Stats.torrent_count) + L" (" + ToSizeString(Stats.torrent_size) + L")"; SetDlgItemText(IDC_STATIC_ANIME_STAT3, text.c_str()); // Taiga text.clear(); text += ToWstr(Stats.connections_succeeded + Stats.connections_failed); if (Stats.connections_failed > 0) text += L" (" + ToWstr(Stats.connections_failed) + L" failed)"; text += L"\n"; text += ToDateString(Stats.uptime) + L"\n"; text += ToWstr(Stats.tigers_harmed); SetDlgItemText(IDC_STATIC_ANIME_STAT4, text.c_str()); }
void Service::ParseLibraryObject(Json::Value& value) { auto& anime_value = value["anime"]; auto& rating_value = value["rating"]; ::anime::Item anime_item; anime_item.SetSource(this->id()); anime_item.SetId(ToWstr(anime_value["id"].asInt()), this->id()); anime_item.SetLastModified(time(nullptr)); // current time int mal_id = value["mal_id"].asInt(); if (mal_id > 0) anime_item.SetId(ToWstr(mal_id), sync::kMyAnimeList); ParseAnimeObject(anime_value, anime_item); anime_item.AddtoUserList(); anime_item.SetMyLastWatchedEpisode(value["episodes_watched"].asInt()); anime_item.SetMyStatus(TranslateMyStatusFrom(StrToWstr(value["status"].asString()))); anime_item.SetMyRewatching(value["rewatching"].asBool()); anime_item.SetMyScore(TranslateMyRatingFrom(StrToWstr(rating_value["value"].asString()), StrToWstr(rating_value["type"].asString()))); AnimeDatabase.UpdateItem(anime_item); }
void Service::GetMetadataByIdV2(Response& response, HttpResponse& http_response) { Json::Value root; if (!ParseResponseBody(response, http_response, root)) return; ::anime::Item anime_item; anime_item.SetSource(this->id()); anime_item.SetId(ToWstr(root["id"].asInt()), this->id()); anime_item.SetLastModified(time(nullptr)); // current time ParseAnimeObjectV2(root, anime_item); AnimeDatabase.UpdateItem(anime_item); }
void FeedConditionDialog::OnOK() { // Set values condition.element = static_cast<FeedFilterElement>(element_combo_.GetCurSel()); condition.op = static_cast<FeedFilterOperator>( operator_combo_.GetItemData(operator_combo_.GetCurSel())); switch (condition.element) { case kFeedFilterElement_Meta_Id: case kFeedFilterElement_Meta_Status: case kFeedFilterElement_Meta_Type: case kFeedFilterElement_User_Status: condition.value = ToWstr(value_combo_.GetItemData(value_combo_.GetCurSel())); break; default: value_combo_.GetText(condition.value); } EndDialog(IDOK); }
void FeedConditionDialog::OnOK() { // Set values condition.element = element_combo_.GetCurSel(); condition.op = operator_combo_.GetItemData(operator_combo_.GetCurSel()); switch (condition.element) { case FEED_FILTER_ELEMENT_META_ID: case FEED_FILTER_ELEMENT_META_STATUS: case FEED_FILTER_ELEMENT_META_TYPE: case FEED_FILTER_ELEMENT_USER_STATUS: condition.value = ToWstr(value_combo_.GetItemData(value_combo_.GetCurSel())); break; default: value_combo_.GetText(condition.value); } // Exit EndDialog(IDOK); }
void UpdateViewMenu() { int item_index, menu_index = -1; menu_index = UI.Menus.GetIndex(L"View"); if (menu_index > -1) { for (unsigned int i = 0; i < MENU.Items.size(); i++) { MENU.Items[i].Checked = false; } item_index = MainDialog.navigation.GetCurrentPage(); for (unsigned int i = 0; i < MENU.Items.size(); i++) { if (MENU.Items[i].Action == L"ViewContent(" + ToWstr(item_index) + L")") { MENU.Items[i].Checked = true; break; } } MENU.Items.back().Checked = Settings.Program.General.hide_sidebar == FALSE; } }
std::wstring GetRelativeTimeString(time_t unix_time, bool append_suffix) { if (!unix_time) return L"Unknown"; time_t time_diff = time(nullptr) - unix_time; Duration duration(std::abs(time_diff)); bool future = time_diff < 0; std::wstring str; auto str_value = [](const float value, const std::wstring& singular, const std::wstring& plural) { long result = std::lround(value); return ToWstr(result) + L" " + (result == 1 ? singular : plural); }; if (duration.seconds() < 90) { str = L"a moment"; } else if (duration.minutes() < 45) { str = str_value(duration.minutes(), L"minute", L"minutes"); } else if (duration.hours() < 22) { str = str_value(duration.hours(), L"hour", L"hours"); } else if (duration.days() < 25) { str = str_value(duration.days(), L"day", L"days"); } else if (duration.days() < 345) { str = str_value(duration.months(), L"month", L"months"); } else { str = str_value(duration.years(), L"year", L"years"); } if (append_suffix) { if (future) { str = L"in " + str; } else { str += L" ago"; } } return str; }
void Announcer::ToMessenger(wstring artist, wstring album, wstring title, BOOL show) { if (title.empty() && show) return; COPYDATASTRUCT cds; WCHAR buffer[256]; wstring wstr = L"\\0Music\\0" + ToWstr(show) + L"\\0{1}\\0" + artist + L"\\0" + title + L"\\0" + album + L"\\0\\0"; wcscpy_s(buffer, 256, wstr.c_str()); cds.dwData = 0x547; cds.lpData = &buffer; cds.cbData = (lstrlenW(buffer) * 2) + 2; HWND hMessenger = NULL; while (hMessenger = FindWindowEx(NULL, hMessenger, L"MsnMsgrUIManager", NULL)) { if (hMessenger > 0) { SendMessage(hMessenger, WM_COPYDATA, NULL, (LPARAM)&cds); } } }
bool Service::RequestSucceeded(Response& response, const HttpResponse& http_response) { switch (http_response.code) { // OK case 200: case 201: return true; // Error default: { Json::Value root; Json::Reader reader; bool parsed = reader.parse(WstrToStr(http_response.body), root); response.data[L"error"] = name() + L" returned an error: "; if (parsed) { response.data[L"error"] += StrToWstr(root["error"].asString()); } else { response.data[L"error"] += L"Unknown error (" + ToWstr(static_cast<int>(http_response.code)) + L")"; } return false; } } }
void EventQueue::Check(bool automatic) { // Check if (items.empty()) { return; } if (!items[index].enabled) { LOG(LevelDebug, L"Item is disabled, removing..."); Remove(index); Check(); return; } if (!Taiga.logged_in) { items[index].reason = L"Not logged in"; return; } if (automatic && !Settings.Program.General.enable_sync) { items[index].reason = L"Synchronization is disabled"; return; } // Compare ID with anime list auto anime_item = AnimeDatabase.FindItem(items[index].anime_id); if (!anime_item) { LOG(LevelWarning, L"Item not found in list, removing... ID: " + ToWstr(items[index].anime_id)); Remove(index); Check(); return; } // Update History.queue.updating = true; MainDialog.ChangeStatus(L"Updating list..."); mal::AnimeValues* anime_values = static_cast<mal::AnimeValues*>(&items[index]); mal::Update(*anime_values, items[index].anime_id, items[index].mode); }
void MainDialog::MainTree::RefreshHistoryCounter() { std::wstring text = L"History"; int count = History.queue.GetItemCount(); if (count > 0) text += L" (" + ToWstr(count) + L")"; SetItem(hti.at(kSidebarItemHistory), text.c_str()); }
LRESULT TorrentDialog::OnNotify(int idCtrl, LPNMHDR pnmh) { Feed* feed = Aggregator.Get(kFeedCategoryLink); if (!feed) return 0; // ListView control if (idCtrl == IDC_LIST_TORRENT) { switch (pnmh->code) { // Column click case LVN_COLUMNCLICK: { LPNMLISTVIEW lplv = (LPNMLISTVIEW)pnmh; int order = 1; if (lplv->iSubItem == list_.GetSortColumn()) order = list_.GetSortOrder() * -1; switch (lplv->iSubItem) { // Episode case 1: list_.Sort(lplv->iSubItem, order, ui::kListSortNumber, ui::ListViewCompareProc); break; // File size case 3: list_.Sort(lplv->iSubItem, order, ui::kListSortFileSize, ui::ListViewCompareProc); break; // Other columns default: list_.Sort(lplv->iSubItem, order, ui::kListSortDefault, ui::ListViewCompareProc); break; } break; } // Check/uncheck case LVN_ITEMCHANGED: { if (!list_.IsVisible()) break; LPNMLISTVIEW pnmv = reinterpret_cast<LPNMLISTVIEW>(pnmh); if (pnmv->uOldState != 0 && (pnmv->uNewState == 0x1000 || pnmv->uNewState == 0x2000)) { int checked_count = 0; for (int i = 0; i < list_.GetItemCount(); i++) { if (list_.GetCheckState(i)) checked_count++; } if (checked_count == 1) { DlgMain.ChangeStatus(L"Marked 1 torrent."); } else { DlgMain.ChangeStatus(L"Marked " + ToWstr(checked_count) + L" torrents."); } FeedItem* feed_item = reinterpret_cast<FeedItem*>(list_.GetItemParam(pnmv->iItem)); if (feed_item) { bool checked = list_.GetCheckState(pnmv->iItem) == TRUE; feed_item->state = checked ? kFeedItemSelected : kFeedItemDiscardedNormal; } } break; } // Double click case NM_DBLCLK: { if (list_.GetSelectedCount() > 0) { LPNMITEMACTIVATE lpnmitem = reinterpret_cast<LPNMITEMACTIVATE>(pnmh); if (lpnmitem->iItem == -1) break; FeedItem* feed_item = reinterpret_cast<FeedItem*>(list_.GetItemParam(lpnmitem->iItem)); if (feed_item) feed->Download(feed_item->index); } break; } // Right click case NM_RCLICK: { LPNMITEMACTIVATE lpnmitem = reinterpret_cast<LPNMITEMACTIVATE>(pnmh); if (lpnmitem->iItem == -1) break; FeedItem* feed_item = reinterpret_cast<FeedItem*>(list_.GetItemParam(lpnmitem->iItem)); if (feed_item) { std::wstring answer = ui::Menus.Show(GetWindowHandle(), 0, 0, L"TorrentListRightClick"); if (answer == L"DownloadTorrent") { feed->Download(feed_item->index); } else if (answer == L"Info") { auto anime_id = feed_item->episode_data.anime_id; if (anime_id) { ShowDlgAnimeInfo(anime_id); } else { ExecuteAction(L"SearchAnime(" + feed_item->episode_data.title + L")"); } } else if (answer == L"DiscardTorrent") { feed_item->state = kFeedItemDiscardedNormal; list_.SetCheckState(lpnmitem->iItem, FALSE); Aggregator.file_archive.push_back(feed_item->title); } else if (answer == L"DiscardTorrents") { auto anime_item = AnimeDatabase.FindItem(feed_item->episode_data.anime_id); if (anime_item) { for (int i = 0; i < list_.GetItemCount(); i++) { feed_item = reinterpret_cast<FeedItem*>(list_.GetItemParam(i)); if (feed_item && feed_item->episode_data.anime_id == anime_item->GetId()) { feed_item->state = kFeedItemDiscardedNormal; list_.SetCheckState(i, FALSE); } } Aggregator.filter_manager.AddFilter( kFeedFilterActionDiscard, kFeedFilterMatchAll, kFeedFilterOptionDefault, true, L"Discard \"" + anime_item->GetTitle() + L"\""); Aggregator.filter_manager.filters.back().AddCondition( kFeedFilterElement_Meta_Id, kFeedFilterOperator_Equals, ToWstr(anime_item->GetId())); } } else if (answer == L"SelectFansub") { int anime_id = feed_item->episode_data.anime_id; std::wstring group_name = feed_item->episode_data.group; if (anime::IsValidId(anime_id) && !group_name.empty()) { for (int i = 0; i < list_.GetItemCount(); i++) { feed_item = reinterpret_cast<FeedItem*>(list_.GetItemParam(i)); if (feed_item && !IsEqual(feed_item->episode_data.group, group_name)) { feed_item->state = kFeedItemDiscardedNormal; list_.SetCheckState(i, FALSE); } } anime::SetFansubFilter(anime_id, group_name); } } else if (answer == L"MoreTorrents") { Search(Settings[taiga::kTorrent_Discovery_SearchUrl], feed_item->episode_data.title); } else if (answer == L"SearchService") { ExecuteAction(L"SearchAnime(" + feed_item->episode_data.title + L")"); } } break; } // Custom draw case NM_CUSTOMDRAW: { LPNMLVCUSTOMDRAW pCD = reinterpret_cast<LPNMLVCUSTOMDRAW>(pnmh); switch (pCD->nmcd.dwDrawStage) { case CDDS_PREPAINT: return CDRF_NOTIFYITEMDRAW; case CDDS_ITEMPREPAINT: return CDRF_NOTIFYSUBITEMDRAW; case CDDS_PREERASE: case CDDS_ITEMPREERASE: return CDRF_NOTIFYPOSTERASE; case CDDS_ITEMPREPAINT | CDDS_SUBITEM: { // Alternate background color if ((pCD->nmcd.dwItemSpec % 2) && !list_.IsGroupViewEnabled()) pCD->clrTextBk = ChangeColorBrightness(GetSysColor(COLOR_WINDOW), -0.03f); FeedItem* feed_item = reinterpret_cast<FeedItem*>(pCD->nmcd.lItemlParam); if (feed_item) { if (Taiga.debug_mode) { // Change background color switch (feed_item->state) { case kFeedItemDiscardedNormal: case kFeedItemDiscardedInactive: case kFeedItemDiscardedHidden: pCD->clrTextBk = ui::kColorLightRed; break; case kFeedItemSelected: pCD->clrTextBk = ui::kColorLightGreen; break; default: pCD->clrTextBk = GetSysColor(COLOR_WINDOW); break; } } // Change text color if (feed_item->state == kFeedItemDiscardedInactive) { pCD->clrText = GetSysColor(COLOR_GRAYTEXT); } else if (feed_item->episode_data.new_episode) { pCD->clrText = GetSysColor(pCD->iSubItem == 1 ? COLOR_HIGHLIGHT : COLOR_WINDOWTEXT); } } return CDRF_NOTIFYPOSTPAINT; } } } } } return 0; }
void EventQueue::Add(EventItem& item, bool save) { auto anime = AnimeDatabase.FindItem(item.anime_id); // Add to user list if (anime && !anime->IsInList()) if (item.mode != HTTP_MAL_AnimeDelete) anime->AddtoUserList(); // Validate values if (anime && anime->IsInList()) { if (item.episode) if (anime->GetMyLastWatchedEpisode() == *item.episode || *item.episode < 0) item.episode.Reset(); if (item.score) if (anime->GetMyScore() == *item.score || *item.score < 0 || *item.score > 10) item.score.Reset(); if (item.status) if (anime->GetMyStatus() == *item.status || *item.status < 1 || *item.status == 5 || *item.status > 6) item.status.Reset(); if (item.enable_rewatching) if (anime->GetMyRewatching() == *item.enable_rewatching) item.enable_rewatching.Reset(); if (item.tags) if (anime->GetMyTags() == *item.tags) item.tags.Reset(); if (item.date_start) if (anime->GetMyDate(anime::DATE_START) == mal::TranslateDateFromApi(*item.date_start)) item.date_start.Reset(); if (item.date_finish) if (anime->GetMyDate(anime::DATE_END) == mal::TranslateDateFromApi(*item.date_finish)) item.date_finish.Reset(); } switch (item.mode) { case HTTP_MAL_AnimeUpdate: if (!item.episode && !item.score && !item.status && !item.enable_rewatching && !item.tags && !item.date_start && !item.date_finish) return; break; } // Edit previous item with the same ID... bool add_new_item = true; if (!History.queue.updating) { for (auto it = items.rbegin(); it != items.rend(); ++it) { if (it->anime_id == item.anime_id && it->enabled) { if (it->mode != HTTP_MAL_AnimeAdd && it->mode != HTTP_MAL_AnimeDelete) { if (!item.episode || (!it->episode && it == items.rbegin())) { if (item.episode) it->episode = *item.episode; if (item.score) it->score = *item.score; if (item.status) it->status = *item.status; if (item.enable_rewatching) it->enable_rewatching = *item.enable_rewatching; if (item.tags) it->tags = *item.tags; if (item.date_start) it->date_start = *item.date_start; if (item.date_finish) it->date_finish = *item.date_finish; add_new_item = false; } if (!add_new_item) { it->mode = HTTP_MAL_AnimeUpdate; it->time = (wstring)GetDate() + L" " + GetTime(); } break; } } } } // ...or add a new one if (add_new_item) { if (item.time.empty()) item.time = (wstring)GetDate() + L" " + GetTime(); items.push_back(item); } if (anime && save) { // Save history->Save(); // Announce if (Taiga.logged_in && item.episode) { anime::Episode episode; episode.anime_id = anime->GetId(); episode.number = ToWstr(*item.episode); Taiga.play_status = PLAYSTATUS_UPDATED; Announcer.Do(ANNOUNCE_TO_HTTP | ANNOUNCE_TO_TWITTER, &episode); } // Check new episode if (item.episode) { anime->SetNewEpisodePath(L""); anime->CheckEpisodes(0); } // Refresh history MainDialog.treeview.RefreshHistoryCounter(); HistoryDialog.RefreshList(); // Refresh anime window if (item.mode == HTTP_MAL_AnimeAdd || item.mode == HTTP_MAL_AnimeDelete || item.status || item.enable_rewatching) { AnimeListDialog.RefreshList(); AnimeListDialog.RefreshTabs(); } else { AnimeListDialog.RefreshListItem(item.anime_id); } // Refresh now playing NowPlayingDialog.Refresh(false, false, false); // Change status if (!Taiga.logged_in) { MainDialog.ChangeStatus(L"\"" + anime->GetTitle() + L"\" is queued for update."); } // Update Check(); } }
bool EvaluateCondition(const FeedFilterCondition& condition, const FeedItem& item) { bool is_numeric = false; std::wstring element; std::wstring value = ReplaceVariables(condition.value, item.episode_data); auto anime = AnimeDatabase.FindItem(item.episode_data.anime_id); switch (condition.element) { case kFeedFilterElement_File_Title: element = item.title; break; case kFeedFilterElement_File_Category: element = item.category; break; case kFeedFilterElement_File_Description: element = item.description; break; case kFeedFilterElement_File_Link: element = item.link; break; case kFeedFilterElement_Meta_Id: if (anime) element = ToWstr(anime->GetId()); is_numeric = true; break; case kFeedFilterElement_Episode_Title: element = item.episode_data.title; break; case kFeedFilterElement_Meta_DateStart: if (anime) element = anime->GetDateStart(); break; case kFeedFilterElement_Meta_DateEnd: if (anime) element = anime->GetDateEnd(); break; case kFeedFilterElement_Meta_Episodes: if (anime) element = ToWstr(anime->GetEpisodeCount()); is_numeric = true; break; case kFeedFilterElement_Meta_Status: if (anime) element = ToWstr(anime->GetAiringStatus()); is_numeric = true; break; case kFeedFilterElement_Meta_Type: if (anime) element = ToWstr(anime->GetType()); is_numeric = true; break; case kFeedFilterElement_User_Status: if (anime) element = ToWstr(anime->GetMyStatus()); is_numeric = true; break; case kFeedFilterElement_Episode_Number: element = ToWstr(anime::GetEpisodeHigh(item.episode_data.number)); is_numeric = true; break; case kFeedFilterElement_Episode_Version: element = item.episode_data.version; if (element.empty()) element = L"1"; is_numeric = true; break; case kFeedFilterElement_Local_EpisodeAvailable: if (anime) element = ToWstr(anime->IsEpisodeAvailable( anime::GetEpisodeHigh(item.episode_data.number))); is_numeric = true; break; case kFeedFilterElement_Episode_Group: element = item.episode_data.group; break; case kFeedFilterElement_Episode_VideoResolution: element = item.episode_data.resolution; break; case kFeedFilterElement_Episode_VideoType: element = item.episode_data.video_type; break; } switch (condition.op) { case kFeedFilterOperator_Equals: if (is_numeric) { if (IsEqual(value, L"True")) return ToInt(element) == TRUE; return ToInt(element) == ToInt(value); } else { if (condition.element == kFeedFilterElement_Episode_VideoResolution) { return anime::TranslateResolution(element) == anime::TranslateResolution(condition.value); } else { return IsEqual(element, value); } } case kFeedFilterOperator_NotEquals: if (is_numeric) { if (IsEqual(value, L"True")) return ToInt(element) == TRUE; return ToInt(element) != ToInt(value); } else { if (condition.element == kFeedFilterElement_Episode_VideoResolution) { return anime::TranslateResolution(element) != anime::TranslateResolution(condition.value); } else { return !IsEqual(element, value); } } case kFeedFilterOperator_IsGreaterThan: if (is_numeric) { return ToInt(element) > ToInt(value); } else { if (condition.element == kFeedFilterElement_Episode_VideoResolution) { return anime::TranslateResolution(element) > anime::TranslateResolution(condition.value); } else { return CompareStrings(element, condition.value) > 0; } } case kFeedFilterOperator_IsGreaterThanOrEqualTo: if (is_numeric) { return ToInt(element) >= ToInt(value); } else { if (condition.element == kFeedFilterElement_Episode_VideoResolution) { return anime::TranslateResolution(element) >= anime::TranslateResolution(condition.value); } else { return CompareStrings(element, condition.value) >= 0; } } case kFeedFilterOperator_IsLessThan: if (is_numeric) { return ToInt(element) < ToInt(value); } else { if (condition.element == kFeedFilterElement_Episode_VideoResolution) { return anime::TranslateResolution(element) < anime::TranslateResolution(condition.value); } else { return CompareStrings(element, condition.value) < 0; } } case kFeedFilterOperator_IsLessThanOrEqualTo: if (is_numeric) { return ToInt(element) <= ToInt(value); } else { if (condition.element == kFeedFilterElement_Episode_VideoResolution) { return anime::TranslateResolution(element) <= anime::TranslateResolution(condition.value); } else { return CompareStrings(element, condition.value) <= 0; } } case kFeedFilterOperator_BeginsWith: return StartsWith(element, value); case kFeedFilterOperator_EndsWith: return EndsWith(element, value); case kFeedFilterOperator_Contains: return InStr(element, value, 0, true) > -1; case kFeedFilterOperator_NotContains: return InStr(element, value, 0, true) == -1; } return false; }