From 0f3b3c4b2d7f6dfc9704666ddc6265d36ed42431 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 13 Feb 2025 17:19:09 -0500 Subject: [PATCH] Adds support for NIP-73 --- .../quartz/nip73ExternalIds/BookId.kt | 39 +++++++++++++++++ .../quartz/nip73ExternalIds/ExternalId.kt | 29 +++++++++++++ .../quartz/nip73ExternalIds/GeohashId.kt | 38 +++++++++++++++++ .../quartz/nip73ExternalIds/HashtagId.kt | 38 +++++++++++++++++ .../quartz/nip73ExternalIds/MovieId.kt | 41 ++++++++++++++++++ .../quartz/nip73ExternalIds/PaperId.kt | 39 +++++++++++++++++ .../nip73ExternalIds/PodcastEpisodeId.kt | 39 +++++++++++++++++ .../quartz/nip73ExternalIds/PodcastFeedId.kt | 39 +++++++++++++++++ .../nip73ExternalIds/PodcastPublisherId.kt | 39 +++++++++++++++++ .../quartz/nip73ExternalIds/UrlId.kt | 42 +++++++++++++++++++ 10 files changed, 383 insertions(+) create mode 100644 quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/BookId.kt create mode 100644 quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/ExternalId.kt create mode 100644 quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/GeohashId.kt create mode 100644 quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/HashtagId.kt create mode 100644 quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/MovieId.kt create mode 100644 quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/PaperId.kt create mode 100644 quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/PodcastEpisodeId.kt create mode 100644 quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/PodcastFeedId.kt create mode 100644 quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/PodcastPublisherId.kt create mode 100644 quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/UrlId.kt diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/BookId.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/BookId.kt new file mode 100644 index 000000000..812f78958 --- /dev/null +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/BookId.kt @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip73ExternalIds + +class BookId( + val isbn: String, + val hint: String? = null, +) : ExternalId { + override fun toScope() = toScope(isbn) + + override fun toKind() = toKind(isbn) + + override fun hint() = hint + + companion object { + // "isbn:9780765382030" + fun toScope(isbn: String) = "isbn:" + isbn.lowercase().replace("-", "") + + fun toKind(isbn: String) = "isbn" + } +} diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/ExternalId.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/ExternalId.kt new file mode 100644 index 000000000..83acbeca6 --- /dev/null +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/ExternalId.kt @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip73ExternalIds + +interface ExternalId { + fun toScope(): String + + fun toKind(): String + + fun hint(): String? +} diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/GeohashId.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/GeohashId.kt new file mode 100644 index 000000000..94c3d1ee5 --- /dev/null +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/GeohashId.kt @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip73ExternalIds + +class GeohashId( + val geohash: String, + val hint: String? = null, +) : ExternalId { + override fun toScope() = toScope(geohash) + + override fun toKind() = toKind(geohash) + + override fun hint() = hint + + companion object { + fun toScope(geohash: String) = "geo:" + geohash.lowercase() + + fun toKind(geohash: String) = "geo" + } +} diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/HashtagId.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/HashtagId.kt new file mode 100644 index 000000000..7ce563364 --- /dev/null +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/HashtagId.kt @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip73ExternalIds + +class HashtagId( + val topic: String, + val hint: String? = null, +) : ExternalId { + override fun toScope() = toScope(topic) + + override fun toKind() = toKind(topic) + + override fun hint() = hint + + companion object { + fun toScope(topic: String) = "#" + topic.lowercase() + + fun toKind(topic: String) = "#" + } +} diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/MovieId.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/MovieId.kt new file mode 100644 index 000000000..be8e316fc --- /dev/null +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/MovieId.kt @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip73ExternalIds + +import kotlin.math.min + +class MovieId( + val isan: String, + val hint: String? = null, +) : ExternalId { + override fun toScope() = toScope(isan) + + override fun toKind() = toKind(isan) + + override fun hint() = hint + + companion object { + // "isan:0000-0000-401A-0000-7" + fun toScope(isan: String) = "isan:" + isan.lowercase().substring(0, min(21, isan.length)) + + fun toKind(isan: String) = "isan" + } +} diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/PaperId.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/PaperId.kt new file mode 100644 index 000000000..1a47e5749 --- /dev/null +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/PaperId.kt @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip73ExternalIds + +class PaperId( + val doi: String, + val hint: String? = null, +) : ExternalId { + override fun toScope() = toScope(doi) + + override fun toKind() = toKind(doi) + + override fun hint() = hint + + companion object { + // "doi:10.1000/182" + fun toScope(doi: String) = "doi:" + doi.lowercase() + + fun toKind(doi: String) = "doi" + } +} diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/PodcastEpisodeId.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/PodcastEpisodeId.kt new file mode 100644 index 000000000..7ce70ae29 --- /dev/null +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/PodcastEpisodeId.kt @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip73ExternalIds + +class PodcastEpisodeId( + val guid: String, + val hint: String? = null, +) : ExternalId { + override fun toScope() = toScope(guid) + + override fun toKind() = toKind(guid) + + override fun hint() = hint + + companion object { + // "isbn:9780765382030" + fun toScope(guid: String) = "podcast:item:guid:" + guid + + fun toKind(guid: String) = "podcast:item:guid" + } +} diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/PodcastFeedId.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/PodcastFeedId.kt new file mode 100644 index 000000000..f1fe33442 --- /dev/null +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/PodcastFeedId.kt @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip73ExternalIds + +class PodcastFeedId( + val guid: String, + val hint: String? = null, +) : ExternalId { + override fun toScope() = toScope(guid) + + override fun toKind() = toKind(guid) + + override fun hint() = hint + + companion object { + // "isbn:9780765382030" + fun toScope(guid: String) = "podcast:guid:" + guid + + fun toKind(guid: String) = "podcast:guid" + } +} diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/PodcastPublisherId.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/PodcastPublisherId.kt new file mode 100644 index 000000000..77d7fbbb7 --- /dev/null +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/PodcastPublisherId.kt @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip73ExternalIds + +class PodcastPublisherId( + val guid: String, + val hint: String? = null, +) : ExternalId { + override fun toScope() = toScope(guid) + + override fun toKind() = toKind(guid) + + override fun hint() = hint + + companion object { + // "isbn:9780765382030" + fun toScope(guid: String) = "podcast:publisher:guid:" + guid + + fun toKind(guid: String) = "podcast:publisher:guid" + } +} diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/UrlId.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/UrlId.kt new file mode 100644 index 000000000..996256fa8 --- /dev/null +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip73ExternalIds/UrlId.kt @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip73ExternalIds + +import com.vitorpamplona.quartz.utils.toStringNoFragment +import com.vitorpamplona.quartz.utils.toStringSchemeHost +import org.czeal.rfc3986.URIReference + +class UrlId( + val url: String, + val hint: String? = null, +) : ExternalId { + override fun toScope() = toScope(url) + + override fun toKind() = toKind(url) + + override fun hint() = hint + + companion object { + fun toScope(url: String) = URIReference.parse(url).normalize().toStringNoFragment() + + fun toKind(url: String) = URIReference.parse(url).normalize().toStringSchemeHost() + } +}