mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
fix(post form): block temporary media links
This commit is contained in:
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "مستضافة خارج 5chan",
|
"media_failed_to_load_source_unknown": "مستضافة خارج 5chan",
|
||||||
"media_failed_to_load_open_source": "افتح الملف الأصلي",
|
"media_failed_to_load_open_source": "افتح الملف الأصلي",
|
||||||
"media_failed_to_load_inline": "فشلت الصورة الخارجية من {{host}}. جرّب VPN.",
|
"media_failed_to_load_inline": "فشلت الصورة الخارجية من {{host}}. جرّب VPN.",
|
||||||
"media_failed_to_load_inline_unknown": "فشلت الصورة الخارجية. جرّب VPN."
|
"media_failed_to_load_inline_unknown": "فشلت الصورة الخارجية. جرّب VPN.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "5chan-এর বাইরে হোস্ট করা",
|
"media_failed_to_load_source_unknown": "5chan-এর বাইরে হোস্ট করা",
|
||||||
"media_failed_to_load_open_source": "মূল ফাইল খুলুন",
|
"media_failed_to_load_open_source": "মূল ফাইল খুলুন",
|
||||||
"media_failed_to_load_inline": "{{host}} থেকে বাইরের ছবি লোড হয়নি। VPN চেষ্টা করুন।",
|
"media_failed_to_load_inline": "{{host}} থেকে বাইরের ছবি লোড হয়নি। VPN চেষ্টা করুন।",
|
||||||
"media_failed_to_load_inline_unknown": "বাইরের ছবি লোড হয়নি। VPN চেষ্টা করুন।"
|
"media_failed_to_load_inline_unknown": "বাইরের ছবি লোড হয়নি। VPN চেষ্টা করুন।",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "Hostováno mimo 5chan",
|
"media_failed_to_load_source_unknown": "Hostováno mimo 5chan",
|
||||||
"media_failed_to_load_open_source": "Otevřít původní soubor",
|
"media_failed_to_load_open_source": "Otevřít původní soubor",
|
||||||
"media_failed_to_load_inline": "Externí obrázek z {{host}} selhal. Zkuste VPN.",
|
"media_failed_to_load_inline": "Externí obrázek z {{host}} selhal. Zkuste VPN.",
|
||||||
"media_failed_to_load_inline_unknown": "Externí obrázek selhal. Zkuste VPN."
|
"media_failed_to_load_inline_unknown": "Externí obrázek selhal. Zkuste VPN.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "Hostet uden for 5chan",
|
"media_failed_to_load_source_unknown": "Hostet uden for 5chan",
|
||||||
"media_failed_to_load_open_source": "Åbn originalfil",
|
"media_failed_to_load_open_source": "Åbn originalfil",
|
||||||
"media_failed_to_load_inline": "Eksternt billede fra {{host}} fejlede. Prøv VPN.",
|
"media_failed_to_load_inline": "Eksternt billede fra {{host}} fejlede. Prøv VPN.",
|
||||||
"media_failed_to_load_inline_unknown": "Eksternt billede fejlede. Prøv VPN."
|
"media_failed_to_load_inline_unknown": "Eksternt billede fejlede. Prøv VPN.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "Nicht auf 5chan gehostet",
|
"media_failed_to_load_source_unknown": "Nicht auf 5chan gehostet",
|
||||||
"media_failed_to_load_open_source": "Originaldatei öffnen",
|
"media_failed_to_load_open_source": "Originaldatei öffnen",
|
||||||
"media_failed_to_load_inline": "Externes Bild von {{host}} fehlgeschlagen. VPN versuchen.",
|
"media_failed_to_load_inline": "Externes Bild von {{host}} fehlgeschlagen. VPN versuchen.",
|
||||||
"media_failed_to_load_inline_unknown": "Externes Bild fehlgeschlagen. VPN versuchen."
|
"media_failed_to_load_inline_unknown": "Externes Bild fehlgeschlagen. VPN versuchen.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "Φιλοξενείται εκτός 5chan",
|
"media_failed_to_load_source_unknown": "Φιλοξενείται εκτός 5chan",
|
||||||
"media_failed_to_load_open_source": "Άνοιγμα αρχικού αρχείου",
|
"media_failed_to_load_open_source": "Άνοιγμα αρχικού αρχείου",
|
||||||
"media_failed_to_load_inline": "Η εξωτερική εικόνα από {{host}} απέτυχε. Δοκιμάστε VPN.",
|
"media_failed_to_load_inline": "Η εξωτερική εικόνα από {{host}} απέτυχε. Δοκιμάστε VPN.",
|
||||||
"media_failed_to_load_inline_unknown": "Η εξωτερική εικόνα απέτυχε. Δοκιμάστε VPN."
|
"media_failed_to_load_inline_unknown": "Η εξωτερική εικόνα απέτυχε. Δοκιμάστε VPN.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -187,6 +187,7 @@
|
|||||||
"filtered_threads": "Filtered threads",
|
"filtered_threads": "Filtered threads",
|
||||||
"no_board_selected_warning": "Please select a board before posting.",
|
"no_board_selected_warning": "Please select a board before posting.",
|
||||||
"invalid_url_alert": "The provided link is not a valid URL.",
|
"invalid_url_alert": "The provided link is not a valid URL.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead.",
|
||||||
"empty_comment_alert": "Cannot post empty comment.",
|
"empty_comment_alert": "Cannot post empty comment.",
|
||||||
"stored_locally": "Stored locally (in {{location}} data), not synced across devices.",
|
"stored_locally": "Stored locally (in {{location}} data), not synced across devices.",
|
||||||
"choose_one": "Choose one:",
|
"choose_one": "Choose one:",
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "Host externo, no 5chan",
|
"media_failed_to_load_source_unknown": "Host externo, no 5chan",
|
||||||
"media_failed_to_load_open_source": "Abrir archivo original",
|
"media_failed_to_load_open_source": "Abrir archivo original",
|
||||||
"media_failed_to_load_inline": "Falló la imagen externa de {{host}}. Prueba una VPN.",
|
"media_failed_to_load_inline": "Falló la imagen externa de {{host}}. Prueba una VPN.",
|
||||||
"media_failed_to_load_inline_unknown": "Falló la imagen externa. Prueba una VPN."
|
"media_failed_to_load_inline_unknown": "Falló la imagen externa. Prueba una VPN.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "میزبان خارجی، نه 5chan",
|
"media_failed_to_load_source_unknown": "میزبان خارجی، نه 5chan",
|
||||||
"media_failed_to_load_open_source": "باز کردن فایل اصلی",
|
"media_failed_to_load_open_source": "باز کردن فایل اصلی",
|
||||||
"media_failed_to_load_inline": "تصویر خارجی از {{host}} بارگیری نشد. VPN را امتحان کنید.",
|
"media_failed_to_load_inline": "تصویر خارجی از {{host}} بارگیری نشد. VPN را امتحان کنید.",
|
||||||
"media_failed_to_load_inline_unknown": "تصویر خارجی بارگیری نشد. VPN را امتحان کنید."
|
"media_failed_to_load_inline_unknown": "تصویر خارجی بارگیری نشد. VPN را امتحان کنید.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "Ulkoinen host, ei 5chan",
|
"media_failed_to_load_source_unknown": "Ulkoinen host, ei 5chan",
|
||||||
"media_failed_to_load_open_source": "Avaa alkuperäinen tiedosto",
|
"media_failed_to_load_open_source": "Avaa alkuperäinen tiedosto",
|
||||||
"media_failed_to_load_inline": "Ulkoinen kuva sivustolta {{host}} epäonnistui. Kokeile VPN:ää.",
|
"media_failed_to_load_inline": "Ulkoinen kuva sivustolta {{host}} epäonnistui. Kokeile VPN:ää.",
|
||||||
"media_failed_to_load_inline_unknown": "Ulkoinen kuva epäonnistui. Kokeile VPN:ää."
|
"media_failed_to_load_inline_unknown": "Ulkoinen kuva epäonnistui. Kokeile VPN:ää.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "Panlabas na host, hindi 5chan",
|
"media_failed_to_load_source_unknown": "Panlabas na host, hindi 5chan",
|
||||||
"media_failed_to_load_open_source": "Buksan ang orihinal na file",
|
"media_failed_to_load_open_source": "Buksan ang orihinal na file",
|
||||||
"media_failed_to_load_inline": "Nabigo ang panlabas na larawan mula sa {{host}}. Subukan ang VPN.",
|
"media_failed_to_load_inline": "Nabigo ang panlabas na larawan mula sa {{host}}. Subukan ang VPN.",
|
||||||
"media_failed_to_load_inline_unknown": "Nabigo ang panlabas na larawan. Subukan ang VPN."
|
"media_failed_to_load_inline_unknown": "Nabigo ang panlabas na larawan. Subukan ang VPN.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "Hôte externe, pas 5chan",
|
"media_failed_to_load_source_unknown": "Hôte externe, pas 5chan",
|
||||||
"media_failed_to_load_open_source": "Ouvrir le fichier original",
|
"media_failed_to_load_open_source": "Ouvrir le fichier original",
|
||||||
"media_failed_to_load_inline": "L'image externe de {{host}} a échoué. Essayez un VPN.",
|
"media_failed_to_load_inline": "L'image externe de {{host}} a échoué. Essayez un VPN.",
|
||||||
"media_failed_to_load_inline_unknown": "L'image externe a échoué. Essayez un VPN."
|
"media_failed_to_load_inline_unknown": "L'image externe a échoué. Essayez un VPN.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "מארח חיצוני, לא 5chan",
|
"media_failed_to_load_source_unknown": "מארח חיצוני, לא 5chan",
|
||||||
"media_failed_to_load_open_source": "פתח את הקובץ המקורי",
|
"media_failed_to_load_open_source": "פתח את הקובץ המקורי",
|
||||||
"media_failed_to_load_inline": "התמונה החיצונית מ-{{host}} נכשלה. נסה VPN.",
|
"media_failed_to_load_inline": "התמונה החיצונית מ-{{host}} נכשלה. נסה VPN.",
|
||||||
"media_failed_to_load_inline_unknown": "התמונה החיצונית נכשלה. נסה VPN."
|
"media_failed_to_load_inline_unknown": "התמונה החיצונית נכשלה. נסה VPN.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "बाहरी होस्ट, 5chan नहीं",
|
"media_failed_to_load_source_unknown": "बाहरी होस्ट, 5chan नहीं",
|
||||||
"media_failed_to_load_open_source": "मूल फ़ाइल खोलें",
|
"media_failed_to_load_open_source": "मूल फ़ाइल खोलें",
|
||||||
"media_failed_to_load_inline": "{{host}} से बाहरी छवि लोड नहीं हुई। VPN आज़माएँ।",
|
"media_failed_to_load_inline": "{{host}} से बाहरी छवि लोड नहीं हुई। VPN आज़माएँ।",
|
||||||
"media_failed_to_load_inline_unknown": "बाहरी छवि लोड नहीं हुई। VPN आज़माएँ।"
|
"media_failed_to_load_inline_unknown": "बाहरी छवि लोड नहीं हुई। VPN आज़माएँ।",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "Külső host, nem 5chan",
|
"media_failed_to_load_source_unknown": "Külső host, nem 5chan",
|
||||||
"media_failed_to_load_open_source": "Eredeti fájl megnyitása",
|
"media_failed_to_load_open_source": "Eredeti fájl megnyitása",
|
||||||
"media_failed_to_load_inline": "A külső kép innen nem töltődött be: {{host}}. Próbálj VPN-t.",
|
"media_failed_to_load_inline": "A külső kép innen nem töltődött be: {{host}}. Próbálj VPN-t.",
|
||||||
"media_failed_to_load_inline_unknown": "A külső kép nem töltődött be. Próbálj VPN-t."
|
"media_failed_to_load_inline_unknown": "A külső kép nem töltődött be. Próbálj VPN-t.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "Host eksternal, bukan 5chan",
|
"media_failed_to_load_source_unknown": "Host eksternal, bukan 5chan",
|
||||||
"media_failed_to_load_open_source": "Buka file asli",
|
"media_failed_to_load_open_source": "Buka file asli",
|
||||||
"media_failed_to_load_inline": "Gambar eksternal dari {{host}} gagal. Coba VPN.",
|
"media_failed_to_load_inline": "Gambar eksternal dari {{host}} gagal. Coba VPN.",
|
||||||
"media_failed_to_load_inline_unknown": "Gambar eksternal gagal. Coba VPN."
|
"media_failed_to_load_inline_unknown": "Gambar eksternal gagal. Coba VPN.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "Host esterno, non 5chan",
|
"media_failed_to_load_source_unknown": "Host esterno, non 5chan",
|
||||||
"media_failed_to_load_open_source": "Apri file originale",
|
"media_failed_to_load_open_source": "Apri file originale",
|
||||||
"media_failed_to_load_inline": "Immagine esterna da {{host}} non caricata. Prova una VPN.",
|
"media_failed_to_load_inline": "Immagine esterna da {{host}} non caricata. Prova una VPN.",
|
||||||
"media_failed_to_load_inline_unknown": "Immagine esterna non caricata. Prova una VPN."
|
"media_failed_to_load_inline_unknown": "Immagine esterna non caricata. Prova una VPN.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "外部ホスト、5chan ではありません",
|
"media_failed_to_load_source_unknown": "外部ホスト、5chan ではありません",
|
||||||
"media_failed_to_load_open_source": "元のファイルを開く",
|
"media_failed_to_load_open_source": "元のファイルを開く",
|
||||||
"media_failed_to_load_inline": "{{host}} の外部画像を読み込めませんでした。VPN を試してください。",
|
"media_failed_to_load_inline": "{{host}} の外部画像を読み込めませんでした。VPN を試してください。",
|
||||||
"media_failed_to_load_inline_unknown": "外部画像を読み込めませんでした。VPN を試してください。"
|
"media_failed_to_load_inline_unknown": "外部画像を読み込めませんでした。VPN を試してください。",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "외부 호스트, 5chan 아님",
|
"media_failed_to_load_source_unknown": "외부 호스트, 5chan 아님",
|
||||||
"media_failed_to_load_open_source": "원본 파일 열기",
|
"media_failed_to_load_open_source": "원본 파일 열기",
|
||||||
"media_failed_to_load_inline": "{{host}}의 외부 이미지를 불러오지 못했습니다. VPN을 시도하세요.",
|
"media_failed_to_load_inline": "{{host}}의 외부 이미지를 불러오지 못했습니다. VPN을 시도하세요.",
|
||||||
"media_failed_to_load_inline_unknown": "외부 이미지를 불러오지 못했습니다. VPN을 시도하세요."
|
"media_failed_to_load_inline_unknown": "외부 이미지를 불러오지 못했습니다. VPN을 시도하세요.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "बाह्य होस्ट, 5chan नाही",
|
"media_failed_to_load_source_unknown": "बाह्य होस्ट, 5chan नाही",
|
||||||
"media_failed_to_load_open_source": "मूळ फाइल उघडा",
|
"media_failed_to_load_open_source": "मूळ फाइल उघडा",
|
||||||
"media_failed_to_load_inline": "{{host}} वरील बाह्य प्रतिमा लोड झाली नाही. VPN वापरून पाहा.",
|
"media_failed_to_load_inline": "{{host}} वरील बाह्य प्रतिमा लोड झाली नाही. VPN वापरून पाहा.",
|
||||||
"media_failed_to_load_inline_unknown": "बाह्य प्रतिमा लोड झाली नाही. VPN वापरून पाहा."
|
"media_failed_to_load_inline_unknown": "बाह्य प्रतिमा लोड झाली नाही. VPN वापरून पाहा.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "Externe host, niet 5chan",
|
"media_failed_to_load_source_unknown": "Externe host, niet 5chan",
|
||||||
"media_failed_to_load_open_source": "Origineel bestand openen",
|
"media_failed_to_load_open_source": "Origineel bestand openen",
|
||||||
"media_failed_to_load_inline": "Externe afbeelding van {{host}} mislukt. Probeer VPN.",
|
"media_failed_to_load_inline": "Externe afbeelding van {{host}} mislukt. Probeer VPN.",
|
||||||
"media_failed_to_load_inline_unknown": "Externe afbeelding mislukt. Probeer VPN."
|
"media_failed_to_load_inline_unknown": "Externe afbeelding mislukt. Probeer VPN.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "Ekstern host, ikke 5chan",
|
"media_failed_to_load_source_unknown": "Ekstern host, ikke 5chan",
|
||||||
"media_failed_to_load_open_source": "Åpne originalfil",
|
"media_failed_to_load_open_source": "Åpne originalfil",
|
||||||
"media_failed_to_load_inline": "Eksternt bilde fra {{host}} kunne ikke lastes. Prøv VPN.",
|
"media_failed_to_load_inline": "Eksternt bilde fra {{host}} kunne ikke lastes. Prøv VPN.",
|
||||||
"media_failed_to_load_inline_unknown": "Eksternt bilde kunne ikke lastes. Prøv VPN."
|
"media_failed_to_load_inline_unknown": "Eksternt bilde kunne ikke lastes. Prøv VPN.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "Zewnętrzny host, nie 5chan",
|
"media_failed_to_load_source_unknown": "Zewnętrzny host, nie 5chan",
|
||||||
"media_failed_to_load_open_source": "Otwórz oryginalny plik",
|
"media_failed_to_load_open_source": "Otwórz oryginalny plik",
|
||||||
"media_failed_to_load_inline": "Obraz zewnętrzny z {{host}} nie załadował się. Spróbuj VPN.",
|
"media_failed_to_load_inline": "Obraz zewnętrzny z {{host}} nie załadował się. Spróbuj VPN.",
|
||||||
"media_failed_to_load_inline_unknown": "Obraz zewnętrzny nie załadował się. Spróbuj VPN."
|
"media_failed_to_load_inline_unknown": "Obraz zewnętrzny nie załadował się. Spróbuj VPN.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "Host externo, não 5chan",
|
"media_failed_to_load_source_unknown": "Host externo, não 5chan",
|
||||||
"media_failed_to_load_open_source": "Abrir arquivo original",
|
"media_failed_to_load_open_source": "Abrir arquivo original",
|
||||||
"media_failed_to_load_inline": "Falha na imagem externa de {{host}}. Tente uma VPN.",
|
"media_failed_to_load_inline": "Falha na imagem externa de {{host}}. Tente uma VPN.",
|
||||||
"media_failed_to_load_inline_unknown": "Falha na imagem externa. Tente uma VPN."
|
"media_failed_to_load_inline_unknown": "Falha na imagem externa. Tente uma VPN.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "Host extern, nu 5chan",
|
"media_failed_to_load_source_unknown": "Host extern, nu 5chan",
|
||||||
"media_failed_to_load_open_source": "Deschide fișierul original",
|
"media_failed_to_load_open_source": "Deschide fișierul original",
|
||||||
"media_failed_to_load_inline": "Imaginea externă de la {{host}} a eșuat. Încearcă VPN.",
|
"media_failed_to_load_inline": "Imaginea externă de la {{host}} a eșuat. Încearcă VPN.",
|
||||||
"media_failed_to_load_inline_unknown": "Imaginea externă a eșuat. Încearcă VPN."
|
"media_failed_to_load_inline_unknown": "Imaginea externă a eșuat. Încearcă VPN.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "Внешний хост, не 5chan",
|
"media_failed_to_load_source_unknown": "Внешний хост, не 5chan",
|
||||||
"media_failed_to_load_open_source": "Открыть исходный файл",
|
"media_failed_to_load_open_source": "Открыть исходный файл",
|
||||||
"media_failed_to_load_inline": "Внешнее изображение с {{host}} не загрузилось. Попробуйте VPN.",
|
"media_failed_to_load_inline": "Внешнее изображение с {{host}} не загрузилось. Попробуйте VPN.",
|
||||||
"media_failed_to_load_inline_unknown": "Внешнее изображение не загрузилось. Попробуйте VPN."
|
"media_failed_to_load_inline_unknown": "Внешнее изображение не загрузилось. Попробуйте VPN.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "Host i jashtëm, jo 5chan",
|
"media_failed_to_load_source_unknown": "Host i jashtëm, jo 5chan",
|
||||||
"media_failed_to_load_open_source": "Hap skedarin origjinal",
|
"media_failed_to_load_open_source": "Hap skedarin origjinal",
|
||||||
"media_failed_to_load_inline": "Imazhi i jashtëm nga {{host}} dështoi. Provoni VPN.",
|
"media_failed_to_load_inline": "Imazhi i jashtëm nga {{host}} dështoi. Provoni VPN.",
|
||||||
"media_failed_to_load_inline_unknown": "Imazhi i jashtëm dështoi. Provoni VPN."
|
"media_failed_to_load_inline_unknown": "Imazhi i jashtëm dështoi. Provoni VPN.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "Extern host, inte 5chan",
|
"media_failed_to_load_source_unknown": "Extern host, inte 5chan",
|
||||||
"media_failed_to_load_open_source": "Öppna originalfil",
|
"media_failed_to_load_open_source": "Öppna originalfil",
|
||||||
"media_failed_to_load_inline": "Extern bild från {{host}} kunde inte läsas in. Prova VPN.",
|
"media_failed_to_load_inline": "Extern bild från {{host}} kunde inte läsas in. Prova VPN.",
|
||||||
"media_failed_to_load_inline_unknown": "Extern bild kunde inte läsas in. Prova VPN."
|
"media_failed_to_load_inline_unknown": "Extern bild kunde inte läsas in. Prova VPN.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "బాహ్య హోస్ట్, 5chan కాదు",
|
"media_failed_to_load_source_unknown": "బాహ్య హోస్ట్, 5chan కాదు",
|
||||||
"media_failed_to_load_open_source": "అసలు ఫైల్ను తెరవండి",
|
"media_failed_to_load_open_source": "అసలు ఫైల్ను తెరవండి",
|
||||||
"media_failed_to_load_inline": "{{host}} నుండి బాహ్య చిత్రం లోడ్ కాలేదు. VPN ప్రయత్నించండి.",
|
"media_failed_to_load_inline": "{{host}} నుండి బాహ్య చిత్రం లోడ్ కాలేదు. VPN ప్రయత్నించండి.",
|
||||||
"media_failed_to_load_inline_unknown": "బాహ్య చిత్రం లోడ్ కాలేదు. VPN ప్రయత్నించండి."
|
"media_failed_to_load_inline_unknown": "బాహ్య చిత్రం లోడ్ కాలేదు. VPN ప్రయత్నించండి.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "โฮสต์ภายนอก ไม่ใช่ 5chan",
|
"media_failed_to_load_source_unknown": "โฮสต์ภายนอก ไม่ใช่ 5chan",
|
||||||
"media_failed_to_load_open_source": "เปิดไฟล์ต้นฉบับ",
|
"media_failed_to_load_open_source": "เปิดไฟล์ต้นฉบับ",
|
||||||
"media_failed_to_load_inline": "โหลดรูปภาพภายนอกจาก {{host}} ไม่สำเร็จ ลอง VPN",
|
"media_failed_to_load_inline": "โหลดรูปภาพภายนอกจาก {{host}} ไม่สำเร็จ ลอง VPN",
|
||||||
"media_failed_to_load_inline_unknown": "โหลดรูปภาพภายนอกไม่สำเร็จ ลอง VPN"
|
"media_failed_to_load_inline_unknown": "โหลดรูปภาพภายนอกไม่สำเร็จ ลอง VPN",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "Harici host, 5chan değil",
|
"media_failed_to_load_source_unknown": "Harici host, 5chan değil",
|
||||||
"media_failed_to_load_open_source": "Orijinal dosyayı aç",
|
"media_failed_to_load_open_source": "Orijinal dosyayı aç",
|
||||||
"media_failed_to_load_inline": "{{host}} harici görseli yüklenemedi. VPN deneyin.",
|
"media_failed_to_load_inline": "{{host}} harici görseli yüklenemedi. VPN deneyin.",
|
||||||
"media_failed_to_load_inline_unknown": "Harici görsel yüklenemedi. VPN deneyin."
|
"media_failed_to_load_inline_unknown": "Harici görsel yüklenemedi. VPN deneyin.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "Зовнішній хост, не 5chan",
|
"media_failed_to_load_source_unknown": "Зовнішній хост, не 5chan",
|
||||||
"media_failed_to_load_open_source": "Відкрити оригінальний файл",
|
"media_failed_to_load_open_source": "Відкрити оригінальний файл",
|
||||||
"media_failed_to_load_inline": "Зовнішнє зображення з {{host}} не завантажилося. Спробуйте VPN.",
|
"media_failed_to_load_inline": "Зовнішнє зображення з {{host}} не завантажилося. Спробуйте VPN.",
|
||||||
"media_failed_to_load_inline_unknown": "Зовнішнє зображення не завантажилося. Спробуйте VPN."
|
"media_failed_to_load_inline_unknown": "Зовнішнє зображення не завантажилося. Спробуйте VPN.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "بیرونی ہوسٹ، 5chan نہیں",
|
"media_failed_to_load_source_unknown": "بیرونی ہوسٹ، 5chan نہیں",
|
||||||
"media_failed_to_load_open_source": "اصل فائل کھولیں",
|
"media_failed_to_load_open_source": "اصل فائل کھولیں",
|
||||||
"media_failed_to_load_inline": "{{host}} سے بیرونی تصویر لوڈ نہیں ہوئی۔ VPN آزمائیں۔",
|
"media_failed_to_load_inline": "{{host}} سے بیرونی تصویر لوڈ نہیں ہوئی۔ VPN آزمائیں۔",
|
||||||
"media_failed_to_load_inline_unknown": "بیرونی تصویر لوڈ نہیں ہوئی۔ VPN آزمائیں۔"
|
"media_failed_to_load_inline_unknown": "بیرونی تصویر لوڈ نہیں ہوئی۔ VPN آزمائیں۔",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "Máy chủ ngoài, không phải 5chan",
|
"media_failed_to_load_source_unknown": "Máy chủ ngoài, không phải 5chan",
|
||||||
"media_failed_to_load_open_source": "Mở tệp gốc",
|
"media_failed_to_load_open_source": "Mở tệp gốc",
|
||||||
"media_failed_to_load_inline": "Không tải được ảnh bên ngoài từ {{host}}. Thử VPN.",
|
"media_failed_to_load_inline": "Không tải được ảnh bên ngoài từ {{host}}. Thử VPN.",
|
||||||
"media_failed_to_load_inline_unknown": "Không tải được ảnh bên ngoài. Thử VPN."
|
"media_failed_to_load_inline_unknown": "Không tải được ảnh bên ngoài. Thử VPN.",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,5 +387,6 @@
|
|||||||
"media_failed_to_load_source_unknown": "外部主机,不是 5chan",
|
"media_failed_to_load_source_unknown": "外部主机,不是 5chan",
|
||||||
"media_failed_to_load_open_source": "打开原始文件",
|
"media_failed_to_load_open_source": "打开原始文件",
|
||||||
"media_failed_to_load_inline": "来自 {{host}} 的外部图片加载失败。试试 VPN。",
|
"media_failed_to_load_inline": "来自 {{host}} 的外部图片加载失败。试试 VPN。",
|
||||||
"media_failed_to_load_inline_unknown": "外部图片加载失败。试试 VPN。"
|
"media_failed_to_load_inline_unknown": "外部图片加载失败。试试 VPN。",
|
||||||
|
"expiring_media_link_alert": "Media from {{domain}} expires quickly. Use a stable media link instead."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ const testState = vi.hoisted(() => ({
|
|||||||
|
|
||||||
vi.mock('react-i18next', () => ({
|
vi.mock('react-i18next', () => ({
|
||||||
useTranslation: () => ({
|
useTranslation: () => ({
|
||||||
t: (key: string) => key,
|
t: (key: string, options?: Record<string, unknown>) => (options?.domain ? `${key}:${options.domain}` : key),
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -401,8 +401,14 @@ describe('PostForm', () => {
|
|||||||
expect(globalThis.alert).toHaveBeenCalledWith('invalid_url_alert');
|
expect(globalThis.alert).toHaveBeenCalledWith('invalid_url_alert');
|
||||||
|
|
||||||
(globalThis.alert as ReturnType<typeof vi.fn>).mockClear();
|
(globalThis.alert as ReturnType<typeof vi.fn>).mockClear();
|
||||||
await dispatchInput(linkInput as HTMLInputElement, '');
|
|
||||||
await dispatchInput(textarea as HTMLTextAreaElement, 'A valid body');
|
await dispatchInput(textarea as HTMLTextAreaElement, 'A valid body');
|
||||||
|
await dispatchInput(linkInput as HTMLInputElement, 'https://i.4cdn.org/gif/file.jpg');
|
||||||
|
await clickByText(table as HTMLTableElement, 'post');
|
||||||
|
expect(globalThis.alert).not.toHaveBeenCalled();
|
||||||
|
expect(container.textContent).toContain('error: expiring_media_link_alert:i.4cdn.org');
|
||||||
|
expect(testState.publishPostMock).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
await dispatchInput(linkInput as HTMLInputElement, '');
|
||||||
await clickByText(table as HTMLTableElement, 'post');
|
await clickByText(table as HTMLTableElement, 'post');
|
||||||
expect(globalThis.alert).toHaveBeenCalledWith('no_board_selected_warning');
|
expect(globalThis.alert).toHaveBeenCalledWith('no_board_selected_warning');
|
||||||
|
|
||||||
|
|||||||
@@ -188,6 +188,11 @@
|
|||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.formError {
|
||||||
|
margin: 8px 0;
|
||||||
|
padding: 6px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.status {
|
.status {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { Comment, setAccount, useAccount, useEditedComment } from '@bitsocial/bi
|
|||||||
import getShortAddress from '../../lib/get-short-address';
|
import getShortAddress from '../../lib/get-short-address';
|
||||||
import useCommunitiesPagesStore from '@bitsocial/bitsocial-react-hooks/dist/stores/communities-pages';
|
import useCommunitiesPagesStore from '@bitsocial/bitsocial-react-hooks/dist/stores/communities-pages';
|
||||||
import { getDisplayMediaInfoType, getLinkMediaInfo } from '../../lib/utils/media-utils';
|
import { getDisplayMediaInfoType, getLinkMediaInfo } from '../../lib/utils/media-utils';
|
||||||
|
import { getExpiringMediaLinkAlert } from '../../lib/utils/media-link-validation-utils';
|
||||||
import { getPublishURLFilename, isValidPublishURL, isValidURL } from '../../lib/utils/url-utils';
|
import { getPublishURLFilename, isValidPublishURL, isValidURL } from '../../lib/utils/url-utils';
|
||||||
import { isAllView, isCatalogView, isModQueueView, isModView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
import { isAllView, isCatalogView, isModQueueView, isModView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||||
import { useAccountCommunityAddresses } from '../../hooks/use-account-community-addresses';
|
import { useAccountCommunityAddresses } from '../../hooks/use-account-community-addresses';
|
||||||
@@ -346,6 +347,7 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid:
|
|||||||
const accountCommunityAddresses = useAccountCommunityAddresses();
|
const accountCommunityAddresses = useAccountCommunityAddresses();
|
||||||
|
|
||||||
const [lengthError, setLengthError] = useState<string | null>(null);
|
const [lengthError, setLengthError] = useState<string | null>(null);
|
||||||
|
const [formError, setFormError] = useState<string | null>(null);
|
||||||
|
|
||||||
const checkContentLength = useRef(
|
const checkContentLength = useRef(
|
||||||
debounce((content: string, t: TFunction) => {
|
debounce((content: string, t: TFunction) => {
|
||||||
@@ -377,6 +379,7 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid:
|
|||||||
|
|
||||||
checkContentLength.cancel();
|
checkContentLength.cancel();
|
||||||
setLengthError(null);
|
setLengthError(null);
|
||||||
|
setFormError(null);
|
||||||
|
|
||||||
if (!currentTitle && !currentContent && !currentUrl) {
|
if (!currentTitle && !currentContent && !currentUrl) {
|
||||||
alert(t('empty_comment_alert'));
|
alert(t('empty_comment_alert'));
|
||||||
@@ -386,6 +389,11 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid:
|
|||||||
alert(t('invalid_url_alert'));
|
alert(t('invalid_url_alert'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const expiringMediaLinkAlert = currentUrl ? getExpiringMediaLinkAlert(currentUrl, t) : null;
|
||||||
|
if (expiringMediaLinkAlert) {
|
||||||
|
setFormError(expiringMediaLinkAlert);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (currentContent.length > 2000) {
|
if (currentContent.length > 2000) {
|
||||||
alert(t('error') + ': ' + t('field_too_long'));
|
alert(t('error') + ': ' + t('field_too_long'));
|
||||||
@@ -432,6 +440,7 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid:
|
|||||||
|
|
||||||
checkContentLength.cancel();
|
checkContentLength.cancel();
|
||||||
setLengthError(null);
|
setLengthError(null);
|
||||||
|
setFormError(null);
|
||||||
|
|
||||||
if (!currentContent && !currentUrl) {
|
if (!currentContent && !currentUrl) {
|
||||||
alert(t('empty_comment_alert'));
|
alert(t('empty_comment_alert'));
|
||||||
@@ -442,6 +451,11 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid:
|
|||||||
alert(t('invalid_url_alert'));
|
alert(t('invalid_url_alert'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const expiringMediaLinkAlert = currentUrl ? getExpiringMediaLinkAlert(currentUrl, t) : null;
|
||||||
|
if (expiringMediaLinkAlert) {
|
||||||
|
setFormError(expiringMediaLinkAlert);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (currentContent.length > 2000) {
|
if (currentContent.length > 2000) {
|
||||||
alert(t('error') + ': ' + t('field_too_long'));
|
alert(t('error') + ': ' + t('field_too_long'));
|
||||||
@@ -527,8 +541,9 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid:
|
|||||||
/>
|
/>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{publishPostError && <div className={styles.error}>{publishPostError}</div>}
|
{formError && <div className={`${styles.error} ${styles.formError}`}>{formError}</div>}
|
||||||
{publishReplyError && <div className={styles.error}>{publishReplyError}</div>}
|
{publishPostError && <div className={`${styles.error} ${styles.formError}`}>{publishPostError}</div>}
|
||||||
|
{publishReplyError && <div className={`${styles.error} ${styles.formError}`}>{publishReplyError}</div>}
|
||||||
{publishReplyStateMessage && <div className={styles.status}>{publishReplyStateMessage}</div>}
|
{publishReplyStateMessage && <div className={styles.status}>{publishReplyStateMessage}</div>}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -414,6 +414,12 @@ describe('ReplyModal', () => {
|
|||||||
expect(container.textContent).toContain('error: invalid_url_alert');
|
expect(container.textContent).toContain('error: invalid_url_alert');
|
||||||
expect(testState.setPublishReplyOptionsMock).toHaveBeenCalledWith({ spoiler: true });
|
expect(testState.setPublishReplyOptionsMock).toHaveBeenCalledWith({ spoiler: true });
|
||||||
|
|
||||||
|
await dispatchInput(linkInput, 'https://temp.sh/example.png');
|
||||||
|
await clickButtonByText('post');
|
||||||
|
|
||||||
|
expect(container.textContent).toContain('error: expiring_media_link_alert:{"domain":"temp.sh"}');
|
||||||
|
expect(testState.publishReplyMock).not.toHaveBeenCalled();
|
||||||
|
|
||||||
await dispatchInput(linkInput, 'https://example.com/file.png');
|
await dispatchInput(linkInput, 'https://example.com/file.png');
|
||||||
await clickButtonByText('post');
|
await clickButtonByText('post');
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { useLocation, useParams } from 'react-router-dom';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import type { TFunction } from 'i18next';
|
import type { TFunction } from 'i18next';
|
||||||
import { setAccount, useAccount } from '@bitsocial/bitsocial-react-hooks';
|
import { setAccount, useAccount } from '@bitsocial/bitsocial-react-hooks';
|
||||||
|
import { getExpiringMediaLinkAlert } from '../../lib/utils/media-link-validation-utils';
|
||||||
import { getPublishURLFilename, isValidPublishURL } from '../../lib/utils/url-utils';
|
import { getPublishURLFilename, isValidPublishURL } from '../../lib/utils/url-utils';
|
||||||
import { isAllView, isModView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
import { isAllView, isModView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||||
import useSelectedTextStore from '../../stores/use-selected-text-store';
|
import useSelectedTextStore from '../../stores/use-selected-text-store';
|
||||||
@@ -103,6 +104,11 @@ const ReplyModal = ({ closeModal, showReplyModal, parentCid, parentNumber, threa
|
|||||||
setError(t('error') + ': ' + t('invalid_url_alert'));
|
setError(t('error') + ': ' + t('invalid_url_alert'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const expiringMediaLinkAlert = currentUrl ? getExpiringMediaLinkAlert(currentUrl, t) : null;
|
||||||
|
if (expiringMediaLinkAlert) {
|
||||||
|
setError(expiringMediaLinkAlert);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
checkContentLengthRef.current.cancel();
|
checkContentLengthRef.current.cancel();
|
||||||
setLengthError(null);
|
setLengthError(null);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ vi.mock('../clipboard-utils', () => ({
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
copyShareLinkToClipboard,
|
copyShareLinkToClipboard,
|
||||||
|
getExpiringMediaLinkHostname,
|
||||||
getHostname,
|
getHostname,
|
||||||
getPublishURLFilename,
|
getPublishURLFilename,
|
||||||
is5chanLink,
|
is5chanLink,
|
||||||
@@ -62,6 +63,15 @@ describe('url-utils', () => {
|
|||||||
expect(getPublishURLFilename('not-a-url')).toBeNull();
|
expect(getPublishURLFilename('not-a-url')).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('detects publish media hosts with temporary links', () => {
|
||||||
|
expect(getExpiringMediaLinkHostname('https://i.4cdn.org/gif/1712345678900.jpg')).toBe('i.4cdn.org');
|
||||||
|
expect(getExpiringMediaLinkHostname('http://litterbox.catbox.moe/u/example.png')).toBe('litterbox.catbox.moe');
|
||||||
|
expect(getExpiringMediaLinkHostname('https://www.tmpfiles.org/dl/123/file.mp4')).toBe('tmpfiles.org');
|
||||||
|
expect(getExpiringMediaLinkHostname('https://cdn.file.kiwi/example')).toBe('file.kiwi');
|
||||||
|
expect(getExpiringMediaLinkHostname('https://example.com/file.png')).toBeNull();
|
||||||
|
expect(getExpiringMediaLinkHostname('not-a-url')).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
it('copies share links for threads and catalog pages using the production fallback base url', async () => {
|
it('copies share links for threads and catalog pages using the production fallback base url', async () => {
|
||||||
await copyShareLinkToClipboard('music.eth', 'thread', 'cid-123');
|
await copyShareLinkToClipboard('music.eth', 'thread', 'cid-123');
|
||||||
expect(testState.copyToClipboardMock).toHaveBeenCalledWith('https://5chan.app/#/music.eth/thread/cid-123');
|
expect(testState.copyToClipboardMock).toHaveBeenCalledWith('https://5chan.app/#/music.eth/thread/cid-123');
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { getExpiringMediaLinkHostname } from './url-utils';
|
||||||
|
|
||||||
|
type TranslateFn = (key: string, options?: Record<string, unknown>) => string;
|
||||||
|
|
||||||
|
export const getExpiringMediaLinkAlert = (url: string, t: TranslateFn): string | null => {
|
||||||
|
const expiringMediaLinkHostname = getExpiringMediaLinkHostname(url);
|
||||||
|
return expiringMediaLinkHostname ? `${t('error')}: ${t('expiring_media_link_alert', { domain: expiringMediaLinkHostname })}` : null;
|
||||||
|
};
|
||||||
@@ -67,6 +67,41 @@ export const normalizePublishURL = (url: string) => {
|
|||||||
return trimmedUrl;
|
return trimmedUrl;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const EXPIRING_MEDIA_LINK_HOSTNAMES = [
|
||||||
|
// 4chan CDN media disappears when threads are pruned, usually after a few hours or days.
|
||||||
|
'i.4cdn.org',
|
||||||
|
// Litterbox temporary uploads can expire after 1 hour, 12 hours, 1 day, or 3 days.
|
||||||
|
'litterbox.catbox.moe',
|
||||||
|
// tmpfiles.org uploads expire after 60 minutes, 6 hours, 12 hours, or 24 hours.
|
||||||
|
'tmpfiles.org',
|
||||||
|
// Filebin uploads are deleted automatically after about 6 days.
|
||||||
|
'filebin.net',
|
||||||
|
// temp.sh files expire after 3 days.
|
||||||
|
'temp.sh',
|
||||||
|
// Termbin pastes are automatically deleted after 1 week.
|
||||||
|
'termbin.com',
|
||||||
|
// Uguu files expire after 3 hours.
|
||||||
|
'uguu.se',
|
||||||
|
// file.kiwi encrypted files are deleted after about 4 days by default.
|
||||||
|
'file.kiwi',
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
const normalizeHostnameForMatching = (hostname: string) => hostname.toLowerCase().replace(/^www\./, '');
|
||||||
|
|
||||||
|
export const getExpiringMediaLinkHostname = (url: string): string | null => {
|
||||||
|
try {
|
||||||
|
const parsedUrl = new URL(normalizePublishURL(url));
|
||||||
|
if (parsedUrl.protocol !== 'https:') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hostname = normalizeHostnameForMatching(parsedUrl.hostname);
|
||||||
|
return EXPIRING_MEDIA_LINK_HOSTNAMES.find((expiringHostname) => hostname === expiringHostname || hostname.endsWith(`.${expiringHostname}`)) || null;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const isValidPublishURL = (url: string) => {
|
export const isValidPublishURL = (url: string) => {
|
||||||
try {
|
try {
|
||||||
return new URL(normalizePublishURL(url)).protocol === 'https:';
|
return new URL(normalizePublishURL(url)).protocol === 'https:';
|
||||||
|
|||||||
Reference in New Issue
Block a user