diff --git a/src/TibiaCharactersCharacter.go b/src/TibiaCharactersCharacter.go
index c9231aa4..282d569b 100644
--- a/src/TibiaCharactersCharacter.go
+++ b/src/TibiaCharactersCharacter.go
@@ -75,11 +75,11 @@ type Killers struct {
// Child of Character
type Deaths struct {
- Time string `json:"time"` // The timestamp when the death occurred.
- Level int `json:"level"` // The level when the death occurred.
- Killers []Killers `json:"killers"` // List of killers involved.
- Assists []Killers `json:"assists"` // List of assists involved.
- Reason string `json:"reason"` // The plain text reason of death.
+ Time string `json:"time"` // The timestamp when the death occurred.
+ Level int `json:"level,omitempty"` // The level when the death occurred.
+ Killers []Killers `json:"killers"` // List of killers involved.
+ Assists []Killers `json:"assists"` // List of assists involved.
+ Reason string `json:"reason"` // The plain text reason of death.
}
// Child of Character
@@ -383,9 +383,9 @@ func TibiaCharactersCharacterImpl(BoxContentHTML string, url string) (CharacterR
return false
}
- // Removing line breaks
+ // Removing line breaks and sanitizing string
CharacterListHTML = TibiaDataHTMLRemoveLinebreaks(CharacterListHTML)
- CharacterListHTML = strings.ReplaceAll(CharacterListHTML, ".
Assisted by", ". Assisted by")
+ CharacterListHTML = strings.ReplaceAll(strings.ReplaceAll(CharacterListHTML, "
", " "), " ", " ")
CharacterListHTML = TibiaDataSanitizeStrings(CharacterListHTML)
dataNoTags := RemoveHtmlTag(CharacterListHTML)
@@ -404,6 +404,7 @@ func TibiaCharactersCharacterImpl(BoxContentHTML string, url string) (CharacterR
initCestIndexer = `CEST`
levelIndexer = `at Level `
killersIndexer = `by `
+ assistedIndexer = `Assisted by `
)
var initIndexer string
@@ -444,6 +445,11 @@ func TibiaCharactersCharacterImpl(BoxContentHTML string, url string) (CharacterR
level := TibiaDataStringToInteger(dataNoTags[levelIdx:endLevelIdx])
+ // if kill is with assist only (and level is set to 25), then we reset level
+ if reasonStart == assistedIndexer && level == 25 {
+ level = 0
+ }
+
killersIdx := strings.Index(
CharacterListHTML, killersIndexer,
) + len(killersIndexer)
@@ -453,10 +459,17 @@ func TibiaCharactersCharacterImpl(BoxContentHTML string, url string) (CharacterR
rawListofKillers := CharacterListHTML[killersIdx:endKillersIdx]
- // if kill is with assist..
- if strings.Contains(dataNoTags, ". Assisted by ") {
- TmpListOfDeath := strings.Split(CharacterListHTML, ". Assisted by ")
- rawListofKillers = TmpListOfDeath[0][killersIdx:]
+ // A death with assist (or with assist only)
+ if strings.Contains(dataNoTags, assistedIndexer) {
+ TmpListOfDeath := strings.Split(CharacterListHTML, assistedIndexer)
+
+ // get a list of killers
+ if reasonStart != assistedIndexer {
+ rawListofKillers = TmpListOfDeath[0][killersIdx:]
+ rawListofKillers = strings.TrimSpace(strings.TrimSuffix(rawListofKillers, "."))
+ } else {
+ rawListofKillers = ""
+ }
TmpAssist := TmpListOfDeath[1]
// get a list of killers
@@ -473,120 +486,128 @@ func TibiaCharactersCharacterImpl(BoxContentHTML string, url string) (CharacterR
for i := range ListOfAssists {
name, isPlayer, isTraded, theSummon := TibiaDataParseKiller(ListOfAssists[i])
- DeathAssists = append(DeathAssists, Killers{
- Name: strings.TrimSuffix(strings.TrimSuffix(name, "."), "."),
- Player: isPlayer,
- Traded: isTraded,
- Summon: theSummon,
- })
+ if name != "" { // Ensure we don't append empty names
+ DeathAssists = append(DeathAssists, Killers{
+ Name: name,
+ Player: isPlayer,
+ Traded: isTraded,
+ Summon: theSummon,
+ })
+ }
}
}
- // get a list of killers
- ListOfKillers := strings.Split(rawListofKillers, ", ")
+ // A death with killers
+ if rawListofKillers != "" {
- const andStr = " and "
- lastItem := ListOfKillers[len(ListOfKillers)-1]
- lastAndIdx := strings.LastIndex(lastItem, andStr)
+ // get a list of killers
+ ListOfKillers := strings.Split(rawListofKillers, ", ")
- if lastAndIdx > -1 {
- if !strings.Contains(lastItem, " -1 {
+ if !strings.Contains(lastItem, "' {
+ state = nonTag
+ }
+ buffer.WriteByte(cur)
+ case closeAchorTag:
+ buffer.WriteByte(cur)
+ if cur == '>' {
+ str := buffer.String()
+
+ str = strings.TrimPrefix(str, " and ")
+ str = strings.TrimSuffix(str, " and ")
+
+ ListOfKillers = append(ListOfKillers, str)
+ buffer.Reset()
+ state = nonTag
+ }
}
- buffer.WriteByte(cur)
- case openAnchorTag:
- if cur == '>' {
- state = nonTag
- }
- buffer.WriteByte(cur)
- case closeAchorTag:
- buffer.WriteByte(cur)
- if cur == '>' {
- str := buffer.String()
+ }
+
+ if buffer.Len() > 0 {
+ str := buffer.String()
+ buffer.Reset()
- str = strings.TrimPrefix(str, " and ")
- str = strings.TrimSuffix(str, " and ")
+ str = strings.TrimPrefix(str, " and ")
+ str = strings.TrimSuffix(str, " and ")
+ if str != "" {
ListOfKillers = append(ListOfKillers, str)
- buffer.Reset()
- state = nonTag
}
}
}
+ }
- if buffer.Len() > 0 {
- str := buffer.String()
- buffer.Reset()
-
- str = strings.TrimPrefix(str, " and ")
- str = strings.TrimSuffix(str, " and ")
-
- if str != "" {
- ListOfKillers = append(ListOfKillers, str)
- }
+ // loop through all killers and append to result
+ for i := range ListOfKillers {
+ name, isPlayer, isTraded, theSummon := TibiaDataParseKiller(ListOfKillers[i])
+ if name != "" { // Ensure we don't append empty names
+ DeathKillers = append(DeathKillers, Killers{
+ Name: name,
+ Player: isPlayer,
+ Traded: isTraded,
+ Summon: theSummon,
+ })
}
}
}
- // loop through all killers and append to result
- for i := range ListOfKillers {
- name, isPlayer, isTraded, theSummon := TibiaDataParseKiller(ListOfKillers[i])
- DeathKillers = append(DeathKillers, Killers{
- Name: strings.TrimSuffix(strings.TrimSuffix(name, "."), "."),
- Player: isPlayer,
- Traded: isTraded,
- Summon: theSummon,
- })
- }
-
// append deadentry to death list
DeathsData = append(DeathsData, Deaths{
Time: time,
@@ -756,6 +777,9 @@ func TibiaDataParseKiller(data string) (string, bool, bool, string) {
data = RemoveHtmlTag(data)
}
+ // remove htlm, spaces and dots from data-string
+ data = strings.TrimSpace(strings.TrimSuffix(strings.TrimSuffix(data, ""), "."))
+
// get summon information
if strings.HasPrefix(data, "a ") || strings.HasPrefix(data, "an ") {
if containsCreaturesWithOf(data) {
diff --git a/src/TibiaCharactersCharacter_test.go b/src/TibiaCharactersCharacter_test.go
index b502ed73..da2c4744 100644
--- a/src/TibiaCharactersCharacter_test.go
+++ b/src/TibiaCharactersCharacter_test.go
@@ -3389,6 +3389,355 @@ func TestNumber13(t *testing.T) {
}
}
+func TestNumber14(t *testing.T) {
+ file, err := static.TestFiles.Open("testdata/characters/Nannorka.html")
+ if err != nil {
+ t.Fatalf("file opening error: %s", err)
+ }
+ defer file.Close()
+
+ data, err := io.ReadAll(file)
+ if err != nil {
+ t.Fatalf("File reading error: %s", err)
+ }
+
+ characterJson, err := TibiaCharactersCharacterImpl(string(data), "")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ assert := assert.New(t)
+ character := characterJson.Character.CharacterInfo
+
+ assert.Equal("Nannorka", character.Name)
+ assert.False(characterJson.Character.DeathsTruncated)
+
+ // validate death data
+ assert.Equal(35, len(characterJson.Character.Deaths))
+ deaths := characterJson.Character.Deaths
+
+ for idx, tc := range []struct {
+ Assists []Killers
+ Killers []Killers
+ Level int
+ Reason string
+ Time string
+ }{
+ {
+ Assists: []Killers{
+ {Name: "Miquudalajarab", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Miquudalajarab.",
+ Time: "2025-02-27T16:20:06Z",
+ },
+ {
+ Assists: []Killers{},
+ Killers: []Killers{
+ {Name: "Satashi Xuuu", Player: true, Traded: false, Summon: ""},
+ },
+ Level: 791,
+ Reason: "Killed at Level 791 by Satashi Xuuu.",
+ Time: "2025-02-27T03:46:47Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Basilicata", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Basilicata.",
+ Time: "2025-02-25T14:11:42Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Tainerd Ruero", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Tainerd Ruero.",
+ Time: "2025-02-15T10:35:03Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Miquudalajarab", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Miquudalajarab.",
+ Time: "2025-02-15T09:45:37Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Basilicata", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Basilicata.",
+ Time: "2025-02-14T16:56:53Z",
+ },
+ {
+ Assists: []Killers{},
+ Killers: []Killers{
+ {Name: "Satashi Xuuu", Player: true, Traded: false, Summon: ""},
+ },
+ Level: 826,
+ Reason: "Killed at Level 826 by Satashi Xuuu.",
+ Time: "2025-02-14T14:56:33Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Miquudalajarab", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Miquudalajarab.",
+ Time: "2025-02-14T13:24:43Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Miquudalajarab", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Miquudalajarab.",
+ Time: "2025-02-14T08:19:51Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Miquudalajarab", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Miquudalajarab.",
+ Time: "2025-02-12T19:38:28Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Tikozera To Calmo", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Tikozera To Calmo.",
+ Time: "2025-02-12T17:37:04Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Basilicata", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Basilicata.",
+ Time: "2025-02-12T17:02:27Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Du nken", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Du nken.",
+ Time: "2025-02-12T16:56:42Z",
+ },
+ {
+ Assists: []Killers{},
+ Killers: []Killers{
+ {Name: "Satashi Xuuu", Player: true, Traded: false, Summon: ""},
+ },
+ Level: 878,
+ Reason: "Killed at Level 878 by Satashi Xuuu.",
+ Time: "2025-02-11T20:00:44Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Basilicata", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Basilicata.",
+ Time: "2025-02-11T16:21:46Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Whiskin", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Whiskin.",
+ Time: "2025-02-11T16:18:28Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Fjunkes", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Fjunkes.",
+ Time: "2025-02-11T16:16:29Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Fjunkes", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Fjunkes.",
+ Time: "2025-02-10T14:57:44Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Whiskin", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Whiskin.",
+ Time: "2025-02-10T14:55:03Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Kaos Mest", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Kaos Mest.",
+ Time: "2025-02-09T12:13:57Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Whiskin", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Whiskin.",
+ Time: "2025-02-09T10:26:48Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Miquudalajarab", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Miquudalajarab.",
+ Time: "2025-02-09T10:09:39Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Guzik Szef", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Guzik Szef.",
+ Time: "2025-02-09T10:06:43Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Whiskin", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Whiskin.",
+ Time: "2025-02-08T18:06:49Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Shensz Khalifa", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Shensz Khalifa.",
+ Time: "2025-02-08T09:19:19Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Taiimo", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Taiimo.",
+ Time: "2025-02-07T17:13:05Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Shensz Khalifa", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Shensz Khalifa.",
+ Time: "2025-02-06T17:51:50Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Miquudalajarab", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Miquudalajarab.",
+ Time: "2025-02-06T17:50:03Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Taiimo", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Taiimo.",
+ Time: "2025-02-06T17:15:54Z",
+ },
+ {
+ Assists: []Killers{},
+ Killers: []Killers{
+ {Name: "Sephea", Player: true, Traded: false, Summon: ""},
+ },
+ Level: 1007,
+ Reason: "Killed at Level 1007 by Sephea.",
+ Time: "2025-02-05T17:03:08Z",
+ },
+ {
+ Assists: []Killers{},
+ Killers: []Killers{
+ {Name: "Satashi Xuuu", Player: true, Traded: false, Summon: ""},
+ },
+ Level: 1016,
+ Reason: "Killed at Level 1016 by Satashi Xuuu.",
+ Time: "2025-02-04T03:42:41Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Rodmago Aesir", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Rodmago Aesir.",
+ Time: "2025-02-03T16:14:53Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Zain Malek", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Zain Malek.",
+ Time: "2025-02-02T10:19:05Z",
+ },
+ {
+ Assists: []Killers{},
+ Killers: []Killers{
+ {Name: "Itzz Xed", Player: true, Traded: false, Summon: ""},
+ },
+ Level: 1042,
+ Reason: "Killed at Level 1042 by Itzz Xed.",
+ Time: "2025-02-02T10:17:25Z",
+ },
+ {
+ Assists: []Killers{
+ {Name: "Rauxzin", Player: true, Traded: false, Summon: ""},
+ },
+ Killers: []Killers{},
+ Reason: "Assisted by Rauxzin.",
+ Time: "2025-02-02T10:11:07Z",
+ },
+ } {
+ assert.True(
+ reflect.DeepEqual(deaths[idx].Assists, tc.Assists),
+ "Wrong assists\nidx: %d\nwant: %#v\n\ngot: %#v",
+ idx, tc.Assists, deaths[idx].Assists,
+ )
+ assert.True(
+ reflect.DeepEqual(deaths[idx].Killers, tc.Killers),
+ "Wrong killers\nidx: %d\nwant: %#v\n\ngot: %#v",
+ idx, tc.Killers, deaths[idx].Killers,
+ )
+ assert.Equal(
+ deaths[idx].Level, tc.Level,
+ "Wrong Level\nidx: %d\nwant: %d\n\ngot: %d",
+ idx, tc.Level, deaths[idx].Level,
+ )
+ assert.Equal(
+ deaths[idx].Reason, tc.Reason,
+ "Wrong Reason\nidx: %d\nwant: %s\n\ngot: %s",
+ idx, tc.Reason, deaths[idx].Reason,
+ )
+ assert.Equal(
+ tc.Time, deaths[idx].Time,
+ "Wrong Time\nidx: %d\nwant: %s\n\ngot: %s",
+ idx, tc.Time, deaths[idx].Time,
+ )
+ }
+}
+
func BenchmarkNumber1(b *testing.B) {
file, err := static.TestFiles.Open("testdata/characters/Darkside Rafa.html")
if err != nil {
diff --git a/src/static/testdata/characters/Nannorka.html b/src/static/testdata/characters/Nannorka.html
new file mode 100644
index 00000000..f13c98c9
--- /dev/null
+++ b/src/static/testdata/characters/Nannorka.html
@@ -0,0 +1,813 @@
+
+
+
+
+ Tibia - Free Multiplayer Online Role Playing Game - Community
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
NO - internet explorer
+
NEW - internet explorer
+
OLD - internet explorer
+
+
+
+
+
+
+
+
+

+

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+
+
+
+
| Name: | Nannorka | | Title: | None (26 titles unlocked) | | Sex: | male | | Vocation: | Royal Paladin | | Level: | 778 | | Achievement Points: | 401 | | World: | Retalia | | Former World: | Obscubra | | Residence: | Kazordoon | | Guild Membership: | Main of the Retro Delusion | | Last Login: | Mar 03 2025, 18:05:32 CET | | Account Status: | Premium Account | | |
| There are no account badges set to be displayed for this character. | | |
| There are no achievements set to be displayed for this character. | | |
| Feb 27 2025, 17:20:06 CET | Assisted by Miquudalajarab. | | Feb 27 2025, 04:46:47 CET | Killed at Level 791 by Satashi Xuuu. | | Feb 25 2025, 15:11:42 CET | Assisted by Basilicata. | | Feb 15 2025, 11:35:03 CET | Assisted by Tainerd Ruero. | | Feb 15 2025, 10:45:37 CET | Assisted by Miquudalajarab. | | Feb 14 2025, 17:56:53 CET | Assisted by Basilicata. | | Feb 14 2025, 15:56:33 CET | Killed at Level 826 by Satashi Xuuu. | | Feb 14 2025, 14:24:43 CET | Assisted by Miquudalajarab. | | Feb 14 2025, 09:19:51 CET | Assisted by Miquudalajarab. | | Feb 12 2025, 20:38:28 CET | Assisted by Miquudalajarab. | | Feb 12 2025, 18:37:04 CET | Assisted by Tikozera To Calmo. | | Feb 12 2025, 18:02:27 CET | Assisted by Basilicata. | | Feb 12 2025, 17:56:42 CET | Assisted by Du nken. | | Feb 11 2025, 21:00:44 CET | Killed at Level 878 by Satashi Xuuu. | | Feb 11 2025, 17:21:46 CET | Assisted by Basilicata. | | Feb 11 2025, 17:18:28 CET | Assisted by Whiskin. | | Feb 11 2025, 17:16:29 CET | Assisted by Fjunkes. | | Feb 10 2025, 15:57:44 CET | Assisted by Fjunkes. | | Feb 10 2025, 15:55:03 CET | Assisted by Whiskin. | | Feb 09 2025, 13:13:57 CET | Assisted by Kaos Mest. | | Feb 09 2025, 11:26:48 CET | Assisted by Whiskin. | | Feb 09 2025, 11:09:39 CET | Assisted by Miquudalajarab. | | Feb 09 2025, 11:06:43 CET | Assisted by Guzik Szef. | | Feb 08 2025, 19:06:49 CET | Assisted by Whiskin. | | Feb 08 2025, 10:19:19 CET | Assisted by Shensz Khalifa. | | Feb 07 2025, 18:13:05 CET | Assisted by Taiimo. | | Feb 06 2025, 18:51:50 CET | Assisted by Shensz Khalifa. | | Feb 06 2025, 18:50:03 CET | Assisted by Miquudalajarab. | | Feb 06 2025, 18:15:54 CET | Assisted by Taiimo. | | Feb 05 2025, 18:03:08 CET | Killed at Level 1007 by Sephea. | | Feb 04 2025, 04:42:41 CET | Killed at Level 1016 by Satashi Xuuu. | | Feb 03 2025, 17:14:53 CET | Assisted by Rodmago Aesir. | | Feb 02 2025, 11:19:05 CET | Assisted by Zain Malek. | | Feb 02 2025, 11:17:25 CET | Killed at Level 1042 by Itzz Xed. | | Feb 02 2025, 11:11:07 CET | Assisted by Rauxzin. | | |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+
+
+
+
+
+
+
+ 
+