3 changed files with 227 additions and 170 deletions
@ -1,98 +1,101 @@
|
||||
#include "utils/srt_parser.hpp" |
||||
|
||||
#include <algorithm> |
||||
#include <cstdio> |
||||
#include <istream> |
||||
#include <sstream> |
||||
#include <string> |
||||
|
||||
#include "engine/assets.hpp" |
||||
#include "utils/language.h" |
||||
|
||||
namespace devilution { |
||||
|
||||
uint64_t ParseSrtTimestamp(std::string_view timestamp) |
||||
{ |
||||
unsigned long long h = 0, m = 0, s = 0, ms = 0; |
||||
if (sscanf(timestamp.data(), "%llu:%llu:%llu,%llu", &h, &m, &s, &ms) == 4 |
||||
|| sscanf(timestamp.data(), "%llu:%llu:%llu.%llu", &h, &m, &s, &ms) == 4) { |
||||
return static_cast<uint64_t>(h * 3600000ULL + m * 60000ULL + s * 1000ULL + ms); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
std::vector<SubtitleEntry> LoadSrtFile(std::string_view subtitlePath) |
||||
{ |
||||
std::vector<SubtitleEntry> subtitles; |
||||
|
||||
std::string pathStr(subtitlePath); |
||||
auto assetData = LoadAsset(pathStr); |
||||
if (!assetData.has_value()) |
||||
return subtitles; |
||||
|
||||
std::string content(assetData->data.get(), assetData->size); |
||||
std::istringstream stream(content); |
||||
std::string line, text; |
||||
uint64_t startTime = 0, endTime = 0; |
||||
|
||||
while (std::getline(stream, line)) { |
||||
// Remove \r if present
|
||||
if (!line.empty() && line.back() == '\r') |
||||
line.pop_back(); |
||||
|
||||
// Skip empty lines (end of subtitle block)
|
||||
if (line.empty()) { |
||||
if (!text.empty() && startTime < endTime) { |
||||
// Remove trailing newline from text
|
||||
if (!text.empty() && text.back() == '\n') |
||||
text.pop_back(); |
||||
subtitles.push_back({ startTime, endTime, text }); |
||||
text.clear(); |
||||
} |
||||
continue; |
||||
} |
||||
|
||||
// Check if line is a number (subtitle index) - skip it
|
||||
if (std::all_of(line.begin(), line.end(), [](char c) { return std::isdigit(static_cast<unsigned char>(c)); })) |
||||
continue; |
||||
|
||||
// Check if line contains --> (timestamp line)
|
||||
const size_t arrowPos = line.find("-->"); |
||||
if (arrowPos != std::string::npos) { |
||||
const std::string startStr = line.substr(0, arrowPos); |
||||
const std::string endStr = line.substr(arrowPos + 3); |
||||
startTime = ParseSrtTimestamp(startStr); |
||||
endTime = ParseSrtTimestamp(endStr); |
||||
continue; |
||||
} |
||||
|
||||
// Otherwise it's subtitle text
|
||||
if (!text.empty()) |
||||
text += "\n"; |
||||
text += line; |
||||
} |
||||
|
||||
// Handle last subtitle if file doesn't end with blank line
|
||||
if (!text.empty() && startTime < endTime) { |
||||
if (!text.empty() && text.back() == '\n') |
||||
text.pop_back(); |
||||
subtitles.push_back({ startTime, endTime, text }); |
||||
} |
||||
|
||||
return subtitles; |
||||
} |
||||
|
||||
std::string GetSubtitleAtTime(const std::vector<SubtitleEntry> &subtitles, uint64_t videoTimeMs) |
||||
{ |
||||
for (const auto &entry : subtitles) { |
||||
if (videoTimeMs >= entry.startTimeMs && videoTimeMs < entry.endTimeMs) { |
||||
// Translate the subtitle text
|
||||
std::string_view translated = LanguageTranslate(entry.text); |
||||
return std::string(translated); |
||||
} |
||||
} |
||||
return ""; |
||||
} |
||||
|
||||
} // namespace devilution
|
||||
|
||||
#include "utils/srt_parser.hpp" |
||||
|
||||
#include <algorithm> |
||||
#include <cstdio> |
||||
#include <istream> |
||||
#include <sstream> |
||||
#include <string> |
||||
|
||||
#include "engine/assets.hpp" |
||||
#include "utils/language.h" |
||||
#include "utils/log.hpp" |
||||
|
||||
namespace devilution { |
||||
|
||||
uint64_t ParseSrtTimestamp(std::string_view timestamp) |
||||
{ |
||||
unsigned long long h = 0, m = 0, s = 0, ms = 0; |
||||
if (sscanf(timestamp.data(), "%llu:%llu:%llu,%llu", &h, &m, &s, &ms) == 4 |
||||
|| sscanf(timestamp.data(), "%llu:%llu:%llu.%llu", &h, &m, &s, &ms) == 4) { |
||||
return static_cast<uint64_t>(h * 3600000ULL + m * 60000ULL + s * 1000ULL + ms); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
std::vector<SubtitleEntry> LoadSrtFile(std::string_view subtitlePath) |
||||
{ |
||||
std::vector<SubtitleEntry> subtitles; |
||||
|
||||
std::string pathStr(subtitlePath); |
||||
auto assetData = LoadAsset(pathStr); |
||||
if (!assetData.has_value()) { |
||||
LogError("Subtitle file not found: {} ({})", subtitlePath, assetData.error()); |
||||
return subtitles; |
||||
} |
||||
|
||||
std::string content(assetData->data.get(), assetData->size); |
||||
std::istringstream stream(content); |
||||
std::string line, text; |
||||
uint64_t startTime = 0, endTime = 0; |
||||
|
||||
while (std::getline(stream, line)) { |
||||
// Remove \r if present
|
||||
if (!line.empty() && line.back() == '\r') |
||||
line.pop_back(); |
||||
|
||||
// Skip empty lines (end of subtitle block)
|
||||
if (line.empty()) { |
||||
if (!text.empty() && startTime < endTime) { |
||||
// Remove trailing newline from text
|
||||
if (!text.empty() && text.back() == '\n') |
||||
text.pop_back(); |
||||
subtitles.push_back({ startTime, endTime, text }); |
||||
text.clear(); |
||||
} |
||||
continue; |
||||
} |
||||
|
||||
// Check if line is a number (subtitle index) - skip it
|
||||
if (std::all_of(line.begin(), line.end(), [](char c) { return std::isdigit(static_cast<unsigned char>(c)); })) |
||||
continue; |
||||
|
||||
// Check if line contains --> (timestamp line)
|
||||
const size_t arrowPos = line.find("-->"); |
||||
if (arrowPos != std::string::npos) { |
||||
const std::string startStr = line.substr(0, arrowPos); |
||||
const std::string endStr = line.substr(arrowPos + 3); |
||||
startTime = ParseSrtTimestamp(startStr); |
||||
endTime = ParseSrtTimestamp(endStr); |
||||
continue; |
||||
} |
||||
|
||||
// Otherwise it's subtitle text
|
||||
if (!text.empty()) |
||||
text += "\n"; |
||||
text += line; |
||||
} |
||||
|
||||
// Handle last subtitle if file doesn't end with blank line
|
||||
if (!text.empty() && startTime < endTime) { |
||||
if (!text.empty() && text.back() == '\n') |
||||
text.pop_back(); |
||||
subtitles.push_back({ startTime, endTime, text }); |
||||
} |
||||
|
||||
return subtitles; |
||||
} |
||||
|
||||
std::string GetSubtitleAtTime(const std::vector<SubtitleEntry> &subtitles, uint64_t videoTimeMs) |
||||
{ |
||||
for (const auto &entry : subtitles) { |
||||
if (videoTimeMs >= entry.startTimeMs && videoTimeMs < entry.endTimeMs) { |
||||
// Translate the subtitle text
|
||||
std::string_view translated = LanguageTranslate(entry.text); |
||||
return std::string(translated); |
||||
} |
||||
} |
||||
return ""; |
||||
} |
||||
|
||||
} // namespace devilution
|
||||
|
||||
|
||||
Loading…
Reference in new issue