Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
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);
    }
Ejemplo n.º 4
0
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."));
    }
  }
}
Ejemplo n.º 5
0
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);
}
Ejemplo n.º 6
0
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;
      }
Ejemplo n.º 7
0
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();
  }
Ejemplo n.º 8
0
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;
}
Ejemplo n.º 9
0
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;
}
Ejemplo n.º 10
0
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();
}
Ejemplo n.º 11
0
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);
  }
}
Ejemplo n.º 12
0
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",");
  }
}
Ejemplo n.º 13
0
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;
}
Ejemplo n.º 14
0
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
}
Ejemplo n.º 15
0
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"";
}
Ejemplo n.º 16
0
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;
}
Ejemplo n.º 17
0
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());
}
Ejemplo n.º 18
0
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);
}
Ejemplo n.º 19
0
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);
}
Ejemplo n.º 20
0
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);
}
Ejemplo n.º 21
0
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);
}
Ejemplo n.º 22
0
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;
  }
}
Ejemplo n.º 23
0
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;
}
Ejemplo n.º 24
0
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);
    }
  }
}
Ejemplo n.º 25
0
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;
    }
  }
}
Ejemplo n.º 26
0
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);
}
Ejemplo n.º 27
0
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());
}
Ejemplo n.º 28
0
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;
}
Ejemplo n.º 29
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();
  }
}
Ejemplo n.º 30
0
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;
}