diff --git a/src/all/yellownote/assets/i18n/messages_en.properties b/src/all/yellownote/assets/i18n/messages_en.properties new file mode 100644 index 000000000..60a2ff325 --- /dev/null +++ b/src/all/yellownote/assets/i18n/messages_en.properties @@ -0,0 +1,80 @@ +filter.sort.title=Sort by +filter.sort.option.last-update=Last Update +filter.sort.option.popularity=Popularity +filter.sort.option.most-comments=Comment Count +filter.sort.option.latest-comments=Latest Comments +filter.header.ignored-when-search=These filters will be ignored when text search is active! +filter.category.title=Category +filter.category.option.theme.xiuren-featured=Theme: Xiuren Featured +filter.category.option.theme.large-scale=Theme: Large Scale +filter.category.option.theme.sex=Theme: Sex +filter.category.option.theme.exposure=Theme: Exposure +filter.category.option.theme.cosplay=Theme: Cosplay +filter.category.option.theme.sex-toy=Theme: Sex Toy +filter.category.option.theme.bondage=Theme: Bondage +filter.category.option.theme.shaved-pussy=Theme: Shaved Pussy +filter.category.option.theme.lesbian=Theme: Lesbian +filter.category.option.theme.with-original-photos=Theme: With Original Photos +filter.category.option.theme.with-video=Theme: With Video(s) +filter.category.option.theme.amateur=Theme: Amateur +filter.category.option.chinese-studios-pans=Chinese Studios: PANS +filter.category.option.chinese-studios-wind-sings=Chinese Studios: Wind sings +filter.category.option.chinese-studios-xing-se=Chinese Studios: Xing Se +filter.category.option.chinese-studios-huang-fu=Chinese Studios: Huang Fu +filter.category.option.chinese-studios-other-studios=Chinese Studios: Other Studios +filter.category.option.chinese-studios-metcn=Chinese Studios: MetCN +filter.category.option.chinese-studios-litu=Chinese Studios: Litu +filter.category.option.chinese-studios-midnight-project=Chinese Studios: Midnight Project +filter.category.option.chinese-studios-pandora=Chinese Studios: Pandora +filter.category.option.chinese-studios-missleg=Chinese Studios: MISSLEG +filter.category.option.chinese-studios-iss=Chinese Studios: ISS +filter.category.option.chinese-studios-aiss=Chinese Studios: AISS +filter.category.option.chinese-studios-au=Chinese Studios: AU +filter.category.option.chinese-studios-beijing-angel=Chinese Studios: Beijing Angel +filter.category.option.chinese-studios-wuji-works=Chinese Studios: Wuji Works +filter.category.option.chinese-studios-pomelo=Chinese Studios: Pomelo +filter.category.option.chinese-studios-sk-silk=Chinese Studios: SK Silk +filter.category.option.chinese-studios-ddy=Chinese Studios: DDY +filter.category.option.chinese-studios-dongguan-vgirls=Chinese Studios: Dongguan VGirls +filter.category.option.chinese-studios-youmei=Chinese Studios: YouMei +filter.category.option.other-photos-chinese-nude=Other Photos: Chinese Nude +filter.category.option.other-photos-korean-nude=Other Photos: Korean Nude +filter.category.option.other-photos-taiwan-nude=Other Photos: Taiwan Nude +filter.category.option.other-photos-other-regions=Other Photos: Other Regions +filter.category.option.xiuren-all=Xiuren: All +filter.category.option.xiuren-leaked=Xiuren: Leaked +filter.category.option.xiuren-huayang=Xiuren: HuaYang +filter.category.option.xiuren-mygirl=Xiuren: MyGirl +filter.category.option.xiuren-imiss=Xiuren: IMiss +filter.category.option.xiuren-miitao=Xiuren: MiiTao +filter.category.option.xiuren-feilin=Xiuren: FEILIN +filter.category.option.xiuren-youwu=Xiuren: YouWu +filter.category.option.xiuren-wings=Xiuren: WingS +filter.category.option.xiuren-ruisg=Xiuren: RUISG +filter.category.option.korean-studios-makemodel=Korean Studios: Makemodel +filter.category.option.korean-studios-pure-media=Korean Studios: Pure Media +filter.category.option.korean-studios-espacia-korea=Korean Studios: Espacia Korea +filter.category.option.korean-studios-loozy=Korean Studios: Loozy +filter.category.option.japanese-studios-graphis=Japanese Studios: Graphis +filter.category.option.japanese-studios-kuni-scan=Japanese Studios: KUNI Scan +filter.category.option.japanese-studios-weekly-post-digital-photo=Japanese Studios: Weekly Post-Digital Photo +filter.category.option.japanese-studios-morning-sexy=Japanese Studios: Morning SEXY +filter.category.option.japanese-studios-prestige=Japanese Studios: Prestige +filter.category.option.japanese-studios-x-city=Japanese Studios: X-City +filter.category.option.japanese-studios-friday=Japanese Studios: FRIDAY +filter.category.option.japanese-studios-super-pose-book=Japanese Studios: Super Pose Book +filter.category.option.japanese-studios-urabon=Japanese Studios: Urabon +filter.category.option.japanese-studios-escape=Japanese Studios: Escape +filter.category.option.japanese-studios-flash=Japanese Studios: Flash +filter.category.option.taiwan-studios-jvid=Taiwan Studios: JVID +filter.category.option.taiwan-studios-fantasy-factory=Taiwan Studios: Fantasy Factory +filter.category.option.taiwan-studios-tpimage=Taiwan Studios: TPimage +filter.category.option.others-ai-photos=Others: AI Photos + +config.domain.title=Domain Settings +config.domain.summary=If the current domain is blocked, you can change it manually here. It will take effect after restarting the app. +config.domain.dialog.title=Domain Settings +config.domain.dialog.message=Default domain: +config.domain.toast.changed-success=Domain changed successfully. It will take effect after restarting the app. +config.domain.toast.changed-failed=Invalid domain! + diff --git a/src/all/yellownote/assets/i18n/messages_es.properties b/src/all/yellownote/assets/i18n/messages_es.properties new file mode 100644 index 000000000..6ce66738a --- /dev/null +++ b/src/all/yellownote/assets/i18n/messages_es.properties @@ -0,0 +1,82 @@ +filter.sort.title=Ordenar por +filter.sort.option.last-update=Última actualización +filter.sort.option.popularity=Contenido más popular +filter.sort.option.most-comments=Más comentarios +filter.sort.option.latest-comments=Comentarios más recientes + +filter.header.ignored-when-search=¡Estos filtros se ignorarán cuando la búsqueda de texto esté activa! + +filter.category.title=Categoría del álbum +filter.category.option.theme.xiuren-featured=Xiuren Gran escala +filter.category.option.theme.large-scale=Gran Escala +filter.category.option.theme.sex=Sexo +filter.category.option.theme.exposure=Exposición +filter.category.option.theme.cosplay=Cosplay +filter.category.option.theme.sex-toy=Juguete Sexual +filter.category.option.theme.bondage=Esclavitud +filter.category.option.theme.shaved-pussy=Coño Afeitado +filter.category.option.theme.lesbian=Lesbiana +filter.category.option.theme.with-original-photos=Con foto original +filter.category.option.theme.with-video=Con Vídeo(s) +filter.category.option.theme.amateur=Aficionada +filter.category.option.chinese-studios-pans=Estudios chinos: PANS +filter.category.option.chinese-studios-wind-sings=Estudios chinos: El viento canta +filter.category.option.chinese-studios-xing-se=Estudios chinos: Xing Se +filter.category.option.chinese-studios-huang-fu=Estudios chinos: Huang Fu +filter.category.option.chinese-studios-other-studios=Estudios chinos: Otros estudios +filter.category.option.chinese-studios-metcn=Estudios chinos: MetCN +filter.category.option.chinese-studios-litu=Estudios chinos: Litu +filter.category.option.chinese-studios-midnight-project=Estudios chinos: Proyecto de medianoche +filter.category.option.chinese-studios-pandora=Estudios chinos: Pandora +filter.category.option.chinese-studios-missleg=Estudios chinos: MISSLEG +filter.category.option.chinese-studios-iss=Estudios chinos: ISS +filter.category.option.chinese-studios-aiss=Estudios chinos: AISS +filter.category.option.chinese-studios-au=Estudios chinos: AU +filter.category.option.chinese-studios-beijing-angel=Estudios chinos: Beijing Angel +filter.category.option.chinese-studios-wuji-works=Estudios chinos: Wuji Works +filter.category.option.chinese-studios-pomelo=Estudios chinos: Pomelo +filter.category.option.chinese-studios-sk-silk=Estudios chinos: SK Silk +filter.category.option.chinese-studios-ddy=Estudios chinos: DDY +filter.category.option.chinese-studios-dongguan-vgirls=Estudios chinos: Dongguan VGirls +filter.category.option.chinese-studios-youmei=Estudios chinos: YouMei +filter.category.option.other-photos-chinese-nude=Otras fotos: Desnuda China +filter.category.option.other-photos-korean-nude=Otras fotos: Desnudo Coreano +filter.category.option.other-photos-taiwan-nude=Otras fotos: Desnuda Taiwan +filter.category.option.other-photos-other-regions=Otras fotos: Otras Regiones +filter.category.option.xiuren-all=Xiuren: all +filter.category.option.xiuren-leaked=Xiuren: Filtrado +filter.category.option.xiuren-huayang=Xiuren: HuaYang +filter.category.option.xiuren-mygirl=Xiuren: MyGirl +filter.category.option.xiuren-imiss=Xiuren: IMiss +filter.category.option.xiuren-miitao=Xiuren: MiiTao +filter.category.option.xiuren-feilin=Xiuren: FEILIN +filter.category.option.xiuren-youwu=Xiuren: YouWu +filter.category.option.xiuren-wings=Xiuren: WingS +filter.category.option.xiuren-ruisg=Xiuren: RUISG +filter.category.option.korean-studios-makemodel=Estudios coreanos: Makemodel +filter.category.option.korean-studios-pure-media=Estudios coreanos: Pure Medios +filter.category.option.korean-studios-espacia-korea=Estudios coreanos: Espacia Korea +filter.category.option.korean-studios-loozy=Estudios coreanos: Loozy +filter.category.option.japanese-studios-graphis=Estudios japonesas: Graphis +filter.category.option.japanese-studios-kuni-scan=Estudios japonesas: KUNI Scan +filter.category.option.japanese-studios-weekly-post-digital-photo=Estudios japonesas: Foto Semanal Post-Digital +filter.category.option.japanese-studios-morning-sexy=Estudios japonesas: Matutinos Sexy +filter.category.option.japanese-studios-prestige=Estudios japonesas: Prestige +filter.category.option.japanese-studios-x-city=Estudios japonesas: X-City +filter.category.option.japanese-studios-friday=Estudios japonesas: FRIDAY +filter.category.option.japanese-studios-super-pose-book=Estudios japonesas: Super Pose Book +filter.category.option.japanese-studios-urabon=Estudios japonesas: Urabon +filter.category.option.japanese-studios-escape=Estudios japonesas: Escape +filter.category.option.japanese-studios-flash=Estudios japonesas: Flash +filter.category.option.taiwan-studios-jvid=Estudios de Taiwán: JVID +filter.category.option.taiwan-studios-fantasy-factory=Estudios de Taiwán: Fantasy Factory +filter.category.option.taiwan-studios-tpimage=Estudios de Taiwán: TPimage +filter.category.option.others-ai-photos=Otras: AI Photos + +config.domain.title=Configuración de dominio +config.domain.summary=Si el dominio actual está bloqueado, puedes cambiarlo manualmente aquí. Se aplicará después de reiniciar la aplicación. +config.domain.dialog.title=Configuración de dominio +config.domain.dialog.message=Dominio predeterminado: +config.domain.toast.changed-success=Dominio cambiado correctamente. Se aplicará tras reiniciar la aplicación. +config.domain.toast.changed-failed=¡Dominio no válido! + diff --git a/src/all/yellownote/assets/i18n/messages_ko.properties b/src/all/yellownote/assets/i18n/messages_ko.properties new file mode 100644 index 000000000..18641b970 --- /dev/null +++ b/src/all/yellownote/assets/i18n/messages_ko.properties @@ -0,0 +1,82 @@ +filter.sort.title=정렬 방식 +filter.sort.option.last-update=업데이트 날짜 +filter.sort.option.popularity=인기 콘텐츠 +filter.sort.option.most-comments=댓글 많은 순 +filter.sort.option.latest-comments=최신 댓글 순 + +filter.header.ignored-when-search=텍스트 검색이 활성화되면 이 필터는 무시됩니다! + +filter.category.title=앨범 분류 +filter.category.option.theme.xiuren-featured=Xiuren 대판 +filter.category.option.theme.large-scale=대판 +filter.category.option.theme.sex=섹스 +filter.category.option.theme.exposure=노출 +filter.category.option.theme.cosplay=Cosplay +filter.category.option.theme.sex-toy=섹스 토이 +filter.category.option.theme.bondage=속박 +filter.category.option.theme.shaved-pussy=면도한 음부 +filter.category.option.theme.lesbian=레즈비언 +filter.category.option.theme.with-original-photos=원본 있음 +filter.category.option.theme.with-video=동영상 포함 +filter.category.option.theme.amateur=아마추어 +filter.category.option.chinese-studios-pans=중국 스튜디오: PANS +filter.category.option.chinese-studios-wind-sings=중국 스튜디오: 바람이 노래한다 +filter.category.option.chinese-studios-xing-se=중국 스튜디오: 싱 세 +filter.category.option.chinese-studios-huang-fu=중국 스튜디오: 황 푸 +filter.category.option.chinese-studios-other-studios=중국 스튜디오: 다른 스튜디오 +filter.category.option.chinese-studios-metcn=중국 스튜디오: MetCN +filter.category.option.chinese-studios-litu=중국 스튜디오: Litu +filter.category.option.chinese-studios-midnight-project=중국 스튜디오: 미드나잇 프로젝트 +filter.category.option.chinese-studios-pandora=중국 스튜디오: Pandora +filter.category.option.chinese-studios-missleg=중국 스튜디오: MISSLEG +filter.category.option.chinese-studios-iss=중국 스튜디오: ISS +filter.category.option.chinese-studios-aiss=중국 스튜디오: AISS +filter.category.option.chinese-studios-au=중국 스튜디오: AU +filter.category.option.chinese-studios-beijing-angel=중국 스튜디오: Beijing Angel +filter.category.option.chinese-studios-wuji-works=중국 스튜디오: Wuji Works +filter.category.option.chinese-studios-pomelo=중국 스튜디오: 포멜로 +filter.category.option.chinese-studios-sk-silk=중국 스튜디오: SK Silk +filter.category.option.chinese-studios-ddy=중국 스튜디오: DDY +filter.category.option.chinese-studios-dongguan-vgirls=중국 스튜디오: Dongguan VGirls +filter.category.option.chinese-studios-youmei=중국 스튜디오: YouMei +filter.category.option.other-photos-chinese-nude=다른 사진들: 중국 누드 +filter.category.option.other-photos-korean-nude=다른 사진들: 한국 누드 +filter.category.option.other-photos-taiwan-nude=다른 사진들: 대만 누드 +filter.category.option.other-photos-other-regions=다른 사진들: 기타 지역 +filter.category.option.xiuren-all=Xiuren: All +filter.category.option.xiuren-leaked=Xiuren: 누출됨 +filter.category.option.xiuren-huayang=Xiuren: HuaYang +filter.category.option.xiuren-mygirl=Xiuren: MyGirl +filter.category.option.xiuren-imiss=Xiuren: IMiss +filter.category.option.xiuren-miitao=Xiuren: MiiTao +filter.category.option.xiuren-feilin=Xiuren: FEILIN +filter.category.option.xiuren-youwu=Xiuren: YouWu +filter.category.option.xiuren-wings=Xiuren: WingS +filter.category.option.xiuren-ruisg=Xiuren: RUISG +filter.category.option.korean-studios-makemodel=한국 스튜디오: Makemodel +filter.category.option.korean-studios-pure-media=한국 스튜디오: Pure Media +filter.category.option.korean-studios-espacia-korea=한국 스튜디오: Espacia Korea +filter.category.option.korean-studios-loozy=한국 스튜디오: Loozy +filter.category.option.japanese-studios-graphis=일본 스튜디오: Graphis +filter.category.option.japanese-studios-kuni-scan=일본 스튜디오: KUNI Scan +filter.category.option.japanese-studios-weekly-post-digital-photo=일본 스튜디오: 주간 포스트 디지털 사진 +filter.category.option.japanese-studios-morning-sexy=일본 스튜디오: 아침 연예 섹시 +filter.category.option.japanese-studios-prestige=일본 스튜디오: Prestige +filter.category.option.japanese-studios-x-city=일본 스튜디오: X-City +filter.category.option.japanese-studios-friday=일본 스튜디오: FRIDAY +filter.category.option.japanese-studios-super-pose-book=일본 스튜디오: Super Pose Book +filter.category.option.japanese-studios-urabon=일본 스튜디오: Urabon +filter.category.option.japanese-studios-escape=일본 스튜디오: Escape +filter.category.option.japanese-studios-flash=일본 스튜디오: Flash +filter.category.option.taiwan-studios-jvid=대만 스튜디오: JVID +filter.category.option.taiwan-studios-fantasy-factory=대만 스튜디오: Fantasy Factory +filter.category.option.taiwan-studios-tpimage=대만 스튜디오: TPimage +filter.category.option.others-ai-photos=기타: AI 사진 + +config.domain.title=도메인 설정 +config.domain.summary=현재 도메인이 차단된 경우, 여기에서 수동으로 변경할 수 있습니다. 앱을 재시작하면 적용됩니다. +config.domain.dialog.title=도메인 설정 +config.domain.dialog.message=기본 도메인: +config.domain.toast.changed-success=도메인이 변경되었습니다. 앱을 재시작하면 적용됩니다. +config.domain.toast.changed-failed=유효하지 않은 도메인입니다! + diff --git a/src/all/yellownote/assets/i18n/messages_zh_hans.properties b/src/all/yellownote/assets/i18n/messages_zh_hans.properties new file mode 100644 index 000000000..0aab0502e --- /dev/null +++ b/src/all/yellownote/assets/i18n/messages_zh_hans.properties @@ -0,0 +1,82 @@ +filter.sort.title=排序方式 +filter.sort.option.last-update=更新时间 +filter.sort.option.popularity=最热内容 +filter.sort.option.most-comments=最多评论 +filter.sort.option.latest-comments=最近评论 + +filter.header.ignored-when-search=以下过滤在文本搜索时会被忽略! + +filter.category.title=专辑分类 +filter.category.option.theme.xiuren-featured=主题: 秀人网特色 +filter.category.option.theme.large-scale=主题: 大尺度 +filter.category.option.theme.sex=主题: 性爱 +filter.category.option.theme.exposure=主题: 露出 +filter.category.option.theme.cosplay=主题: Cosplay +filter.category.option.theme.sex-toy=主题: 道具 +filter.category.option.theme.bondage=主题: 捆绑 +filter.category.option.theme.shaved-pussy=主题: 白虎 +filter.category.option.theme.lesbian=主题: 女同 +filter.category.option.theme.with-original-photos=主题: 有原图 +filter.category.option.theme.with-video=主题: 有视频 +filter.category.option.theme.amateur=主题: 业余自拍 +filter.category.option.chinese-studios-pans=中国工作室: PANS +filter.category.option.chinese-studios-wind-sings=中国工作室: 风吟鸟唱 +filter.category.option.chinese-studios-xing-se=中国工作室: 行色 +filter.category.option.chinese-studios-huang-fu=中国工作室: 黄甫 +filter.category.option.chinese-studios-other-studios=中国工作室: 其他中国工作室 +filter.category.option.chinese-studios-metcn=中国工作室: 相约中国 +filter.category.option.chinese-studios-litu=中国工作室: 丽图 +filter.category.option.chinese-studios-midnight-project=中国工作室: 深夜企划 +filter.category.option.chinese-studios-pandora=中国工作室: 潘多拉 +filter.category.option.chinese-studios-missleg=中国工作室: 蜜丝 +filter.category.option.chinese-studios-iss=中国工作室: ISS系列 +filter.category.option.chinese-studios-aiss=中国工作室: 爱丝 +filter.category.option.chinese-studios-au=中国工作室: AU +filter.category.option.chinese-studios-beijing-angel=中国工作室: 北京天使 +filter.category.option.chinese-studios-wuji-works=中国工作室: 无忌影社 +filter.category.option.chinese-studios-pomelo=中国工作室: 蜜柚摄影 +filter.category.option.chinese-studios-sk-silk=中国工作室: SK丝库 +filter.category.option.chinese-studios-ddy=中国工作室: DDY +filter.category.option.chinese-studios-dongguan-vgirls=中国工作室: 东莞V女郎 +filter.category.option.chinese-studios-youmei=中国工作室: 尤美 +filter.category.option.other-photos-chinese-nude=各国其他套图: 国模套图 +filter.category.option.other-photos-korean-nude=各国其他套图: 韩模套图 +filter.category.option.other-photos-taiwan-nude=各国其他套图: 台模套图 +filter.category.option.other-photos-other-regions=各国其他套图: 其他地区套图 +filter.category.option.xiuren-all=秀人网旗下: 全部秀人旗下 +filter.category.option.xiuren-leaked=秀人网旗下: 私购流出 +filter.category.option.xiuren-huayang=秀人网旗下: 花漾 +filter.category.option.xiuren-mygirl=秀人网旗下: 美媛馆 +filter.category.option.xiuren-imiss=秀人网旗下: 爱蜜社 +filter.category.option.xiuren-miitao=秀人网旗下: 蜜桃社 +filter.category.option.xiuren-feilin=秀人网旗下: FEILIN嗲囡囡 +filter.category.option.xiuren-youwu=秀人网旗下: 尤物馆 +filter.category.option.xiuren-wings=秀人网旗下: 影私荟 +filter.category.option.xiuren-ruisg=秀人网旗下: 瑞丝馆 +filter.category.option.korean-studios-makemodel=韩国工作室: Makemodel +filter.category.option.korean-studios-pure-media=韩国工作室: Pure Media +filter.category.option.korean-studios-espacia-korea=韩国工作室: Espacia Korea +filter.category.option.korean-studios-loozy=韩国工作室: Loozy +filter.category.option.japanese-studios-graphis=日本工作室: Graphis +filter.category.option.japanese-studios-kuni-scan=日本工作室: KUNI Scan +filter.category.option.japanese-studios-weekly-post-digital-photo=日本工作室: 周刊ポストデジタル写真集 +filter.category.option.japanese-studios-morning-sexy=日本工作室: アサ芸SEXY +filter.category.option.japanese-studios-prestige=日本工作室: Prestige +filter.category.option.japanese-studios-x-city=日本工作室: X-City +filter.category.option.japanese-studios-friday=日本工作室: FRIDAY +filter.category.option.japanese-studios-super-pose-book=日本工作室: Super Pose Book +filter.category.option.japanese-studios-urabon=日本工作室: Urabon +filter.category.option.japanese-studios-escape=日本工作室: Escape +filter.category.option.japanese-studios-flash=日本工作室: FLASHデジタル写真集 +filter.category.option.taiwan-studios-jvid=台湾工作室: JVID +filter.category.option.taiwan-studios-fantasy-factory=台湾工作室: Fantasy Factory +filter.category.option.taiwan-studios-tpimage=台湾工作室: TPimage +filter.category.option.others-ai-photos=其他套图: AI图区 + +config.domain.title=域名设置 +config.domain.summary=如果当前域名被封,可在此手动更换。重启应用后生效。 +config.domain.dialog.title=域名设置 +config.domain.dialog.message=默认域名: +config.domain.toast.changed-success=已更换域名,重启应用后生效。 +config.domain.toast.changed-failed=无效域名! + diff --git a/src/all/yellownote/assets/i18n/messages_zh_hant.properties b/src/all/yellownote/assets/i18n/messages_zh_hant.properties new file mode 100644 index 000000000..c58ebbc48 --- /dev/null +++ b/src/all/yellownote/assets/i18n/messages_zh_hant.properties @@ -0,0 +1,80 @@ +filter.sort.title=排序方式 +filter.sort.option.last-update=更新時間 +filter.sort.option.popularity=最熱門內容 +filter.sort.option.most-comments=最多評論 +filter.sort.option.latest-comments=最新評論 + +filter.category.title=專輯分類 +filter.category.option.theme.xiuren-featured=主題: 秀人網特色 +filter.category.option.theme.large-scale=主題: 大尺度 +filter.category.option.theme.sex=主題: 性愛 +filter.category.option.theme.exposure=主題: 露出 +filter.category.option.theme.cosplay=主題: Cosplay +filter.category.option.theme.sex-toy=主題: 道具 +filter.category.option.theme.bondage=主題: 捆綁 +filter.category.option.theme.shaved-pussy=主題: 白虎 +filter.category.option.theme.lesbian=主題: 女同 +filter.category.option.theme.with-original-photos=主題: 有原圖 +filter.category.option.theme.with-video=主題: 有影片 +filter.category.option.theme.amateur=主題: 業餘自拍 +filter.category.option.chinese-studios-pans=中國工作室: PANS +filter.category.option.chinese-studios-wind-sings=中國工作室: 風吟鳥唱 +filter.category.option.chinese-studios-xing-se=中國工作室: 行色 +filter.category.option.chinese-studios-huang-fu=中國工作室: 黃甫 +filter.category.option.chinese-studios-other-studios=中國工作室: 其他中國工作室 +filter.category.option.chinese-studios-metcn=中國工作室: 相約中國 +filter.category.option.chinese-studios-litu=中國工作室: 麗圖 +filter.category.option.chinese-studios-midnight-project=中國工作室: 深夜企劃 +filter.category.option.chinese-studios-pandora=中國工作室: 潘多菈 +filter.category.option.chinese-studios-missleg=中國工作室: 蜜絲 +filter.category.option.chinese-studios-iss=中國工作室: ISS係列 +filter.category.option.chinese-studios-aiss=中國工作室: 愛絲 +filter.category.option.chinese-studios-au=中國工作室: AU +filter.category.option.chinese-studios-beijing-angel=中國工作室: 北京天使 +filter.category.option.chinese-studios-wuji-works=中國工作室: 無忌影社 +filter.category.option.chinese-studios-pomelo=中國工作室: 蜜柚攝影 +filter.category.option.chinese-studios-sk-silk=中國工作室: SK絲庫 +filter.category.option.chinese-studios-ddy=中國工作室: DDY +filter.category.option.chinese-studios-dongguan-vgirls=中國工作室: 東莞V女郎 +filter.category.option.chinese-studios-youmei=中國工作室: 尤美 +filter.category.option.other-photos-chinese-nude=各國其他套圖: 國模套圖 +filter.category.option.other-photos-korean-nude=各國其他套圖: 韓模套圖 +filter.category.option.other-photos-taiwan-nude=各國其他套圖: 臺模套圖 +filter.category.option.other-photos-other-regions=各國其他套圖: 其他地區套圖 +filter.category.option.xiuren-all=秀人網旗下: 全部秀人旗下 +filter.category.option.xiuren-leaked=秀人網旗下: 私購流出 +filter.category.option.xiuren-huayang=秀人網旗下: 花漾 +filter.category.option.xiuren-mygirl=秀人網旗下: 美媛館 +filter.category.option.xiuren-imiss=秀人網旗下: 愛蜜社 +filter.category.option.xiuren-miitao=秀人網旗下: 蜜桃社 +filter.category.option.xiuren-feilin=秀人網旗下: FEILIN嗲囡囡 +filter.category.option.xiuren-youwu=秀人網旗下: 尤物館 +filter.category.option.xiuren-wings=秀人網旗下: 影私荟 +filter.category.option.xiuren-ruisg=秀人網旗下: 瑞絲館 +filter.category.option.korean-studios-makemodel=韓國工作室: Makemodel +filter.category.option.korean-studios-pure-media=韓國工作室: Pure Media +filter.category.option.korean-studios-espacia-korea=韓國工作室: Espacia Korea +filter.category.option.korean-studios-loozy=韓國工作室: Loozy +filter.category.option.japanese-studios-graphis=日本工作室: Graphis +filter.category.option.japanese-studios-kuni-scan=日本工作室: KUNI Scan +filter.category.option.japanese-studios-weekly-post-digital-photo=日本工作室: 週刊ポストデジタル寫真集 +filter.category.option.japanese-studios-morning-sexy=日本工作室: アサ芸SEXY +filter.category.option.japanese-studios-prestige=日本工作室: Prestige +filter.category.option.japanese-studios-x-city=日本工作室: X-City +filter.category.option.japanese-studios-friday=日本工作室: FRIDAY +filter.category.option.japanese-studios-super-pose-book=日本工作室: Super Pose Book +filter.category.option.japanese-studios-urabon=日本工作室: Urabon +filter.category.option.japanese-studios-escape=日本工作室: Escape +filter.category.option.japanese-studios-flash=日本工作室: FLASHデジタル寫真集 +filter.category.option.taiwan-studios-jvid=臺灣工作室: JVID +filter.category.option.taiwan-studios-fantasy-factory=臺灣工作室: Fantasy Factory +filter.category.option.taiwan-studios-tpimage=臺灣工作室: TPimage +filter.category.option.others-ai-photos=其他套圖: AI圖區 + +config.domain.title=網域設定 +config.domain.summary=若目前網域遭封鎖,可在此手動更換。重新啟動應用後生效。 +config.domain.dialog.title=網域設定 +config.domain.dialog.message=預設網域: +config.domain.toast.changed-success=網域已更換,重新啟動應用後生效。 +config.domain.toast.changed-failed=無效的網域! + diff --git a/src/all/yellownote/build.gradle b/src/all/yellownote/build.gradle new file mode 100644 index 000000000..a09ed699b --- /dev/null +++ b/src/all/yellownote/build.gradle @@ -0,0 +1,12 @@ +ext { + extName = 'YellowNote' + extClass = '.YellowNoteSourceFactory' + extVersionCode = 1 + isNsfw = true +} + +apply from: "$rootDir/common.gradle" + +dependencies { + implementation(project(':lib:i18n')) +} diff --git a/src/all/yellownote/res/mipmap-hdpi/ic_launcher.png b/src/all/yellownote/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..df0f96fe6 Binary files /dev/null and b/src/all/yellownote/res/mipmap-hdpi/ic_launcher.png differ diff --git a/src/all/yellownote/res/mipmap-mdpi/ic_launcher.png b/src/all/yellownote/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..907f8a155 Binary files /dev/null and b/src/all/yellownote/res/mipmap-mdpi/ic_launcher.png differ diff --git a/src/all/yellownote/res/mipmap-xhdpi/ic_launcher.png b/src/all/yellownote/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..addf9b557 Binary files /dev/null and b/src/all/yellownote/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/src/all/yellownote/res/mipmap-xxhdpi/ic_launcher.png b/src/all/yellownote/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..0bfcbda5f Binary files /dev/null and b/src/all/yellownote/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/src/all/yellownote/res/mipmap-xxxhdpi/ic_launcher.png b/src/all/yellownote/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..49969bf07 Binary files /dev/null and b/src/all/yellownote/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/src/all/yellownote/src/eu/kanade/tachiyomi/extension/all/yellownote/JsonPExt.kt b/src/all/yellownote/src/eu/kanade/tachiyomi/extension/all/yellownote/JsonPExt.kt new file mode 100644 index 000000000..893fae055 --- /dev/null +++ b/src/all/yellownote/src/eu/kanade/tachiyomi/extension/all/yellownote/JsonPExt.kt @@ -0,0 +1,5 @@ +package eu.kanade.tachiyomi.extension.all.yellownote + +import org.jsoup.nodes.Element + +fun Element.parentText(): String? = parent()?.text() diff --git a/src/all/yellownote/src/eu/kanade/tachiyomi/extension/all/yellownote/SimpleParsedHttpSource.kt b/src/all/yellownote/src/eu/kanade/tachiyomi/extension/all/yellownote/SimpleParsedHttpSource.kt new file mode 100644 index 000000000..7017b8c4a --- /dev/null +++ b/src/all/yellownote/src/eu/kanade/tachiyomi/extension/all/yellownote/SimpleParsedHttpSource.kt @@ -0,0 +1,42 @@ +package eu.kanade.tachiyomi.extension.all.yellownote + +import eu.kanade.tachiyomi.source.model.SManga +import eu.kanade.tachiyomi.source.online.ParsedHttpSource +import org.jsoup.nodes.Document +import org.jsoup.nodes.Element + +abstract class SimpleParsedHttpSource : ParsedHttpSource() { + + abstract fun simpleMangaSelector(): String + + abstract fun simpleMangaFromElement(element: Element): SManga + + abstract fun simpleNextPageSelector(): String? + + // region popular + override fun popularMangaSelector() = simpleMangaSelector() + override fun popularMangaNextPageSelector() = simpleNextPageSelector() + + override fun popularMangaFromElement(element: Element) = simpleMangaFromElement(element) + // endregion + + // region last + override fun latestUpdatesSelector() = simpleMangaSelector() + override fun latestUpdatesFromElement(element: Element) = simpleMangaFromElement(element) + + override fun latestUpdatesNextPageSelector() = simpleNextPageSelector() + // endregion + + // region search + override fun searchMangaSelector() = simpleMangaSelector() + override fun searchMangaFromElement(element: Element) = simpleMangaFromElement(element) + + override fun searchMangaNextPageSelector() = simpleNextPageSelector() + // endregion + + override fun chapterListSelector() = simpleMangaSelector() + override fun imageUrlParse(document: Document): String { + throw UnsupportedOperationException() + } + // endregion +} diff --git a/src/all/yellownote/src/eu/kanade/tachiyomi/extension/all/yellownote/YellowNote.kt b/src/all/yellownote/src/eu/kanade/tachiyomi/extension/all/yellownote/YellowNote.kt new file mode 100644 index 000000000..3b6b906ae --- /dev/null +++ b/src/all/yellownote/src/eu/kanade/tachiyomi/extension/all/yellownote/YellowNote.kt @@ -0,0 +1,157 @@ +package eu.kanade.tachiyomi.extension.all.yellownote + +import androidx.preference.PreferenceScreen +import eu.kanade.tachiyomi.extension.all.yellownote.YellowNoteFilters.SortSelector +import eu.kanade.tachiyomi.extension.all.yellownote.YellowNotePreferences.baseUrl +import eu.kanade.tachiyomi.extension.all.yellownote.YellowNotePreferences.preferenceMigration +import eu.kanade.tachiyomi.lib.i18n.Intl +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.source.ConfigurableSource +import eu.kanade.tachiyomi.source.model.Filter +import eu.kanade.tachiyomi.source.model.FilterList +import eu.kanade.tachiyomi.source.model.Page +import eu.kanade.tachiyomi.source.model.SChapter +import eu.kanade.tachiyomi.source.model.SManga +import eu.kanade.tachiyomi.source.model.UpdateStrategy +import eu.kanade.tachiyomi.util.asJsoup +import keiyoushi.utils.firstInstance +import keiyoushi.utils.getPreferences +import keiyoushi.utils.tryParse +import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.Request +import okhttp3.Response +import org.jsoup.nodes.Document +import org.jsoup.nodes.Element +import java.text.SimpleDateFormat +import java.util.Locale + +class YellowNote( + override val lang: String, + private val subdomain: String? = null, +) : SimpleParsedHttpSource(), ConfigurableSource { + + override val baseUrl by lazy { preferences.baseUrl(subdomain) } + + override val name = "小黄书" + + override val supportsLatest = true + + override val client = network.cloudflareClient + + private val preferences = getPreferences { preferenceMigration() } + + override fun headersBuilder() = super.headersBuilder() + .add("Referer", "$baseUrl/") + + private val intl = Intl( + language = lang, + baseLanguage = YellowNoteSourceFactory.BASE_LANGUAGE, + availableLanguages = YellowNoteSourceFactory.SUPPORT_LANGUAGES, + classLoader = this::class.java.classLoader!!, + ) + + private val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.US) + + private val styleUrlRegex = """url\(['"]?([^'"]+)['"]?\)""".toRegex() + + override fun setupPreferenceScreen(screen: PreferenceScreen) { + YellowNotePreferences.buildPreferences(screen.context, intl) + .forEach(screen::addPreference) + } + + override fun simpleMangaSelector() = "div.article > div.list > div.item:not([class*=item exoclick_300x500])" + + override fun simpleMangaFromElement(element: Element): SManga { + if (element.hasClass("amateur")) { + return simpleMangaFromElementByAmateur(element) + } + + return SManga.create().apply { + val imgEl = element.selectFirst("img")!! + val titleAppend = element.selectFirst("div.tag > div")?.text()?.let { "($it)" }.orEmpty() + title = "${imgEl.attr("alt")}$titleAppend" + + thumbnail_url = imgEl.absUrl("src") + update_strategy = UpdateStrategy.ONLY_FETCH_ONCE + setUrlWithoutDomain(element.selectFirst("a")!!.absUrl("href")) + } + } + + // /amateurs + private fun simpleMangaFromElementByAmateur(element: Element) = SManga.create().apply { + val titleAppend = element.selectFirst("div.tag > div")?.text()?.let { "($it)" }.orEmpty() + title = "${element.selectFirst("div:nth-child(3)")!!.text()}$titleAppend" + + thumbnail_url = element.selectFirst(".img")?.attr("style") + ?.let { styleUrlRegex.find(it) } + ?.groupValues + ?.get(1) + + update_strategy = UpdateStrategy.ONLY_FETCH_ONCE + setUrlWithoutDomain(element.selectFirst("a[href]")!!.absUrl("href")) + } + + override fun simpleNextPageSelector() = "div.pager:first-of-type a[current] + a[href]" + + override fun popularMangaRequest(page: Int) = GET("$baseUrl/photos/sort-hot/$page.html", headers) + + override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/photos/$page.html", headers) + + override fun mangaDetailsParse(document: Document) = SManga.create().apply { + val tabEl = document.selectFirst("div#tab_1")!! + val titleAppend = tabEl.selectFirst("i.fa.fa-picture-o")?.parentText()?.let { "($it)" }.orEmpty() + title = "${tabEl.selectFirst("i.fa.fa-address-card-o")!!.parentText()!!}$titleAppend" + + author = tabEl.select("div.models > a").joinToString { it.text() } + genre = tabEl.select("div.contentTag").joinToString { it.text() } + status = SManga.COMPLETED + description = tabEl.selectFirst("i.fa.fa-calendar")?.text() + update_strategy = UpdateStrategy.ONLY_FETCH_ONCE + } + + override fun chapterFromElement(element: Element) = throw UnsupportedOperationException() + override fun chapterListParse(response: Response): List { + val doc = response.asJsoup() + val dateUploadStr = doc.selectFirst("i.fa.fa-calendar")?.text() + val dateUpload = dateFormat.tryParse(dateUploadStr) + val maxPage = doc.select("div.pager:first-of-type a:not([class])").last()?.text()?.toInt() ?: 1 + val basePageUrl = response.request.url.toString() + .removeSuffix(".html") + return (maxPage downTo 1).map { page -> + SChapter.create().apply { + chapter_number = 0F + setUrlWithoutDomain("$basePageUrl/$page.html") + name = "Page $page" + date_upload = dateUpload + } + } + } + + override fun pageListParse(document: Document): List { + return document.select("div.article.mask .photos img.cr_only") + .mapIndexed { i, imgEl -> Page(i, imageUrl = imgEl!!.absUrl("src")) } + } + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + val categorySelector = filters.firstInstance() + val sortSelector = filters.firstInstance() + val uriPart = when { + query.isBlank() -> categorySelector.toUriPart() + else -> "photos/keyword-$query" + } + + val httpUrl = baseUrl.toHttpUrl().newBuilder() + .addPathSegments(uriPart) + .addPathSegment(sortSelector.toUriPart()) + .addPathSegments("$page.html") + .build() + return GET(httpUrl, headers) + } + + override fun getFilterList() = FilterList( + YellowNoteFilters.createSortSelector(intl), + Filter.Separator(), + Filter.Header(intl["filter.header.ignored-when-search"]), + YellowNoteFilters.createCategorySelector(intl), + ) +} diff --git a/src/all/yellownote/src/eu/kanade/tachiyomi/extension/all/yellownote/YellowNoteFilters.kt b/src/all/yellownote/src/eu/kanade/tachiyomi/extension/all/yellownote/YellowNoteFilters.kt new file mode 100644 index 000000000..45710f175 --- /dev/null +++ b/src/all/yellownote/src/eu/kanade/tachiyomi/extension/all/yellownote/YellowNoteFilters.kt @@ -0,0 +1,139 @@ +package eu.kanade.tachiyomi.extension.all.yellownote + +import eu.kanade.tachiyomi.lib.i18n.Intl +import eu.kanade.tachiyomi.source.model.Filter + +class YellowNoteFilters { + + data class SortOption(val name: String, val urlPart: String = "") { + override fun toString() = this.name + } + + class SortSelector(name: String, private val vals: Array) : + Filter.Select(name, vals) { + fun toUriPart() = vals[state].urlPart + } + + data class CategoryOption(val name: String, val uriPart: String) { + override fun toString() = this.name + } + + class CategorySelector(name: String, values: Array) : Filter.Select(name, values) { + fun toUriPart() = values[state].uriPart + } + + companion object { + fun createSortSelector(intl: Intl) = SortSelector( + intl["filter.sort.title"], + arrayOf( + SortOption(intl["filter.sort.option.last-update"]), + SortOption(intl["filter.sort.option.popularity"], "sort-hot"), + SortOption(intl["filter.sort.option.most-comments"], "sort-comment"), + SortOption(intl["filter.sort.option.latest-comments"], "sort-recent"), + ), + ) + + private fun themeCategoryOptions(intl: Intl) = listOf( + CategoryOption(intl["filter.category.option.theme.xiuren-featured"], "photos/album-1"), + CategoryOption(intl["filter.category.option.theme.large-scale"], "photos/album-2"), + CategoryOption(intl["filter.category.option.theme.sex"], "photos/album-3"), + CategoryOption(intl["filter.category.option.theme.exposure"], "photos/album-4"), + CategoryOption(intl["filter.category.option.theme.cosplay"], "photos/album-5"), + CategoryOption(intl["filter.category.option.theme.sex-toy"], "photos/album-6"), + CategoryOption(intl["filter.category.option.theme.bondage"], "photos/album-7"), + CategoryOption(intl["filter.category.option.theme.shaved-pussy"], "photos/album-8"), + CategoryOption(intl["filter.category.option.theme.lesbian"], "photos/album-9"), + CategoryOption(intl["filter.category.option.theme.with-original-photos"], "photos/album-10"), + CategoryOption(intl["filter.category.option.theme.with-video"], "photos/album-11"), + CategoryOption(intl["filter.category.option.theme.amateur"], "amateurs"), + ) + + private fun chinaStudiosCategoryOptions(intl: Intl) = listOf( + CategoryOption(intl["filter.category.option.chinese-studios-pans"], "photos/series-6310ce9b90056"), + CategoryOption(intl["filter.category.option.chinese-studios-wind-sings"], "photos/series-6666a7ac3ba9c"), + CategoryOption(intl["filter.category.option.chinese-studios-xing-se"], "photos/series-64f44d99ce673"), + CategoryOption(intl["filter.category.option.chinese-studios-huang-fu"], "photos/series-665f8bafab4bc"), + CategoryOption(intl["filter.category.option.chinese-studios-other-studios"], "photos/series-665f7d787d681"), + CategoryOption(intl["filter.category.option.chinese-studios-metcn"], "photos/series-5f1dcdeaee582"), + CategoryOption(intl["filter.category.option.chinese-studios-litu"], "photos/series-5f1d784995865"), + CategoryOption(intl["filter.category.option.chinese-studios-midnight-project"], "photos/series-638e5a60b1770"), + CategoryOption(intl["filter.category.option.chinese-studios-pandora"], "photos/series-5f23c44cd66bd"), + CategoryOption(intl["filter.category.option.chinese-studios-missleg"], "photos/series-5f2089564c6c2"), + CategoryOption(intl["filter.category.option.chinese-studios-iss"], "photos/series-646c69b675f3d"), + CategoryOption(intl["filter.category.option.chinese-studios-aiss"], "photos/series-5f15f389e993e"), + CategoryOption(intl["filter.category.option.chinese-studios-au"], "photos/series-5f60b98248a81"), + CategoryOption(intl["filter.category.option.chinese-studios-beijing-angel"], "photos/series-622c7f95220a4"), + CategoryOption(intl["filter.category.option.chinese-studios-wuji-works"], "photos/series-619a92aa1fa7a"), + CategoryOption(intl["filter.category.option.chinese-studios-pomelo"], "photos/series-676c3e9b90749"), + CategoryOption(intl["filter.category.option.chinese-studios-sk-silk"], "photos/series-5f382ba894af4"), + CategoryOption(intl["filter.category.option.chinese-studios-ddy"], "photos/series-5f15f727df393"), + CategoryOption(intl["filter.category.option.chinese-studios-dongguan-vgirls"], "photos/series-5f22ea422221c"), + CategoryOption(intl["filter.category.option.chinese-studios-youmei"], "photos/series-61b997728043b"), + ) + + private fun otherPhotosCategoryOptions(intl: Intl) = listOf( + CategoryOption(intl["filter.category.option.other-photos-chinese-nude"], "photos/series-64be21c972ca4"), + CategoryOption(intl["filter.category.option.other-photos-korean-nude"], "photos/series-64be22b4a0fa0"), + CategoryOption(intl["filter.category.option.other-photos-taiwan-nude"], "photos/series-64be21ef4cc51"), + CategoryOption(intl["filter.category.option.other-photos-other-regions"], "photos/series-64be239ce73d4"), + ) + + private fun xiuRenCategoryOptions(intl: Intl) = listOf( + CategoryOption(intl["filter.category.option.xiuren-all"], "photos/series-6660093348354"), + CategoryOption(intl["filter.category.option.xiuren-leaked"], "photos/series-66600a3a227ee"), + CategoryOption(intl["filter.category.option.xiuren-huayang"], "photos/series-5fc4ce40386af"), + CategoryOption(intl["filter.category.option.xiuren-mygirl"], "photos/series-5f1495dbda4de"), + CategoryOption(intl["filter.category.option.xiuren-imiss"], "photos/series-5f71afc92d8ab"), + CategoryOption(intl["filter.category.option.xiuren-miitao"], "photos/series-5f1dd5a7ebe9a"), + CategoryOption(intl["filter.category.option.xiuren-feilin"], "photos/series-5f14a3105d3e8"), + CategoryOption(intl["filter.category.option.xiuren-youwu"], "photos/series-60673bec9dd11"), + CategoryOption(intl["filter.category.option.xiuren-wings"], "photos/series-63d435352808c"), + CategoryOption(intl["filter.category.option.xiuren-ruisg"], "photos/series-61263de287e2f"), + ) + + private fun koreanStudiosCategoryOptions(intl: Intl) = listOf( + CategoryOption(intl["filter.category.option.korean-studios-makemodel"], "photos/series-665f81885f103"), + CategoryOption(intl["filter.category.option.korean-studios-pure-media"], "photos/series-6224e755e21f4"), + CategoryOption(intl["filter.category.option.korean-studios-espacia-korea"], "photos/series-665a2385a2367"), + CategoryOption(intl["filter.category.option.korean-studios-loozy"], "photos/series-62888afad416b"), + ) + + private fun japaneseStudiosCategoryOptions(intl: Intl) = listOf( + CategoryOption(intl["filter.category.option.japanese-studios-graphis"], "photos/series-6450b47c9db0b"), + CategoryOption(intl["filter.category.option.japanese-studios-kuni-scan"], "photos/series-66f9665804471"), + CategoryOption(intl["filter.category.option.japanese-studios-weekly-post-digital-photo"], "photos/series-66e68b9c96ab0"), + CategoryOption(intl["filter.category.option.japanese-studios-morning-sexy"], "photos/series-670d7142b3d88"), + CategoryOption(intl["filter.category.option.japanese-studios-prestige"], "photos/series-670791f5f2f0f"), + CategoryOption(intl["filter.category.option.japanese-studios-x-city"], "photos/series-66fb8cca706ae"), + CategoryOption(intl["filter.category.option.japanese-studios-friday"], "photos/series-66659e2d94489"), + CategoryOption(intl["filter.category.option.japanese-studios-super-pose-book"], "photos/series-62a0a15911f16"), + CategoryOption(intl["filter.category.option.japanese-studios-urabon"], "photos/series-6692ea004cc75"), + CategoryOption(intl["filter.category.option.japanese-studios-escape"], "photos/series-66603af933ec9"), + CategoryOption(intl["filter.category.option.japanese-studios-flash"], "photos/series-672a2029d6a32"), + ) + + private fun taiwanStudiosCategoryOptions(intl: Intl) = listOf( + CategoryOption(intl["filter.category.option.taiwan-studios-jvid"], "photos/series-637b2029d2347"), + CategoryOption(intl["filter.category.option.taiwan-studios-fantasy-factory"], "photos/series-5f889afb37619"), + CategoryOption(intl["filter.category.option.taiwan-studios-tpimage"], "photos/series-5f7a0a80d3d66"), + ) + + private fun otherCategoryOptions(intl: Intl) = listOf( + CategoryOption(intl["filter.category.option.others-ai-photos"], "photos/series-6443d480eb757"), + ) + + fun createCategorySelector(intl: Intl) = CategorySelector( + intl["filter.category.title"], + listOf( + themeCategoryOptions(intl), + taiwanStudiosCategoryOptions(intl), + chinaStudiosCategoryOptions(intl), + otherCategoryOptions(intl), + koreanStudiosCategoryOptions(intl), + japaneseStudiosCategoryOptions(intl), + otherPhotosCategoryOptions(intl), + xiuRenCategoryOptions(intl), + ).flatten().toTypedArray(), + ) + } +} diff --git a/src/all/yellownote/src/eu/kanade/tachiyomi/extension/all/yellownote/YellowNotePreferences.kt b/src/all/yellownote/src/eu/kanade/tachiyomi/extension/all/yellownote/YellowNotePreferences.kt new file mode 100644 index 000000000..14ae63886 --- /dev/null +++ b/src/all/yellownote/src/eu/kanade/tachiyomi/extension/all/yellownote/YellowNotePreferences.kt @@ -0,0 +1,75 @@ +package eu.kanade.tachiyomi.extension.all.yellownote + +import android.content.Context +import android.content.SharedPreferences +import android.widget.Toast +import androidx.preference.EditTextPreference +import eu.kanade.tachiyomi.lib.i18n.Intl +import okhttp3.HttpUrl.Companion.toHttpUrl + +object YellowNotePreferences { + + private const val PS_KEY_ROOT = "XChina" + private const val PS_KEY_DOMAIN = "$PS_KEY_ROOT::DOMAIN" + private const val PS_KEY_DOMAIN_DEFAULT = "$PS_KEY_DOMAIN::DEFAULT" + private const val PS_KEY_DOMAIN_OVERRIDE = "$PS_KEY_DOMAIN::OVERRIDE" + + private const val DEFAULT_DOMAIN = "https://xchina.co" + + private fun SharedPreferences.getStringOrDefaultIfBlank(key: String, defValue: String): String { + val value = getString(key, defValue)!! + return value.ifBlank { defValue } + } + + internal fun SharedPreferences.preferenceMigration() { + // refresh when DEFAULT_DOMAIN update + val defaultDomain = getStringOrDefaultIfBlank(PS_KEY_DOMAIN_DEFAULT, DEFAULT_DOMAIN) + if (DEFAULT_DOMAIN != defaultDomain) { + edit() + .putString(PS_KEY_DOMAIN_DEFAULT, DEFAULT_DOMAIN) + .putString(PS_KEY_DOMAIN_OVERRIDE, DEFAULT_DOMAIN) + .apply() + } + } + + internal fun SharedPreferences.baseUrl(subdomain: String?): String { + val httpUrl = getStringOrDefaultIfBlank(PS_KEY_DOMAIN_OVERRIDE, DEFAULT_DOMAIN).toHttpUrl() + + val newHost = when { + httpUrl.host.split('.').size > 2 || subdomain == null -> httpUrl.host + else -> "$subdomain.${httpUrl.host}" + } + + return httpUrl.newBuilder() + .scheme("https") + .host(newHost) + .build() + .toString() + .removeSuffix("/") + } + + internal fun buildPreferences(context: Context, intl: Intl): List { + return listOf( + EditTextPreference(context).apply { + key = PS_KEY_DOMAIN_OVERRIDE + title = intl["config.domain.title"] + summary = intl["config.domain.summary"] + dialogTitle = intl["config.domain.dialog.title"] + dialogMessage = "${intl["config.domain.dialog.message"]}$DEFAULT_DOMAIN" + + setDefaultValue(DEFAULT_DOMAIN) + setOnPreferenceChangeListener { _, newValue -> + try { + (newValue as String).toHttpUrl() + } catch (e: IllegalArgumentException) { + Toast.makeText(context, intl["config.domain.toast.changed-failed"], Toast.LENGTH_LONG).show() + return@setOnPreferenceChangeListener false + } + + Toast.makeText(context, intl["config.domain.toast.changed-success"], Toast.LENGTH_LONG).show() + true + } + }, + ) + } +} diff --git a/src/all/yellownote/src/eu/kanade/tachiyomi/extension/all/yellownote/YellowNoteSourceFactory.kt b/src/all/yellownote/src/eu/kanade/tachiyomi/extension/all/yellownote/YellowNoteSourceFactory.kt new file mode 100644 index 000000000..f458324ed --- /dev/null +++ b/src/all/yellownote/src/eu/kanade/tachiyomi/extension/all/yellownote/YellowNoteSourceFactory.kt @@ -0,0 +1,25 @@ +package eu.kanade.tachiyomi.extension.all.yellownote + +import eu.kanade.tachiyomi.source.SourceFactory + +class YellowNoteSourceFactory : SourceFactory { + + companion object { + const val BASE_LANGUAGE = "en" + val SUPPORT_LANGUAGES = setOf( + "en", + "es", + "ko", + "zh-Hans", + "zh-Hant", + ) + } + + override fun createSources() = listOf( + YellowNote("en", "en"), + YellowNote("es", "es"), + YellowNote("ko", "kr"), + YellowNote("zh-Hans"), + YellowNote("zh-Hant", "tw"), + ) +}