├── .github └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── README.md ├── models ├── net_disk_model.dart ├── picture_model.dart ├── novel_model.dart ├── video_model.dart └── music_model.dart └── examples └── examples.json /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Allin是一款非常灵活的软件,支流浏览图片、音乐、小说、影视、资源。用户可以自定义制作并添加插件源,以便浏览各种不同类型的资源。 3 | 4 | 下载地址: 5 | 6 | 在本项目的Releases中进行下载 7 | 8 | --- 9 | 10 | 如果你是刚来的,可以试着添加示例源 11 | 12 | 请点击 [快速开始](https://github.com/cuifengcn/allin-browser/wiki/%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B) 13 | 14 | --- 15 | 16 | 17 | ![](https://files.mdnice.com/user/38310/5e1f63ab-d625-4077-bb7d-327d521d900c.png) 18 | 19 | 20 | ![](https://files.mdnice.com/user/38310/21839605-c545-477c-91ed-b6a9d17d7d84.png) 21 | 22 | 23 | ![](https://files.mdnice.com/user/38310/41a479c4-5a1a-4ae1-9164-8a3db49cd8df.png) 24 | 25 | 26 | --- 27 | 28 | 如果你想学习如何制作源 29 | 30 | 请点击 [实例教程:制作一个图片源](https://github.com/cuifengcn/allin-browser/wiki/%E5%AE%9E%E4%BE%8B%E6%95%99%E7%A8%8B%EF%BC%9A%E5%88%B6%E4%BD%9C%E4%B8%80%E4%B8%AA%E5%9B%BE%E7%89%87%E6%BA%90) 31 | 32 | --- 33 | 34 | 如果你想制作自己的源,将其添加到软件中 35 | 36 | 请点击 [教程:创建源](https://github.com/cuifengcn/allin-browser/wiki/%E6%95%99%E7%A8%8B%EF%BC%9A%E5%88%9B%E5%BB%BA%E6%BA%90) 37 | 38 | --- 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug/描述bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce/复现方式** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior/期待效果** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots/截图** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):/操作系统** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context/其他** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /models/net_disk_model.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | class NetDiskSource { 4 | final String id; //id 5 | final String title; //标题 6 | final String detailUrl; //详情页地址 7 | final String? introduce; //介绍 8 | final List? imageList; //介绍图片url列表 9 | final List? tags; // 类型列表 10 | final String? datetime; //发布时间 11 | final int? readNum; //阅读量 12 | final int? commentNum; //评论量 13 | final int? thumbNum; //点赞量 14 | late final Map extra; //额外信息 15 | 16 | NetDiskSource({ 17 | required this.id, 18 | required this.title, 19 | required this.detailUrl, 20 | this.introduce, 21 | this.imageList, 22 | this.tags, 23 | this.datetime, 24 | this.readNum, 25 | this.commentNum, 26 | this.thumbNum, 27 | Map? extra, 28 | }) { 29 | this.extra = (extra?.map((k, v) => MapEntry(k.toString(), v))) ?? {}; 30 | } 31 | 32 | static fromJson(Map data) { 33 | return NetDiskSource( 34 | id: data['id'] as String, 35 | title: data['title'] as String, 36 | detailUrl: data['detailUrl'] as String, 37 | introduce: data['introduce'] as String?, 38 | imageList: data['imageList']?.map((e) => e.toString()).toList() as List?, 39 | tags: data['tags']?.map((e) => e.toString()).toList() as List?, 40 | datetime: data['datetime'] as String?, 41 | readNum: data['readNum'] as int?, 42 | commentNum: data['commentNum'] as int?, 43 | thumbNum: data['thumbNum'] as int?, 44 | extra: data['extra']?.map((k, v) => MapEntry(k as String, v as dynamic)) 45 | as Map?, 46 | ); 47 | } 48 | 49 | toJson() { 50 | return { 51 | 'id': id, 52 | 'title': title, 53 | 'detailUrl': detailUrl, 54 | 'introduce': introduce, 55 | 'imageList': imageList, 56 | 'tags': tags, 57 | 'datetime': datetime, 58 | 'readNum': readNum, 59 | 'commentNum': commentNum, 60 | 'thumbNum': thumbNum, 61 | 'extra': extra, 62 | }; 63 | } 64 | } 65 | 66 | class ResultNetDiskSources { 67 | final List sources; 68 | final int currPage; 69 | final int totalPage; 70 | 71 | ResultNetDiskSources({ 72 | required this.sources, 73 | required this.currPage, 74 | required this.totalPage, 75 | }); 76 | 77 | static fromJson(Map data) { 78 | return ResultNetDiskSources( 79 | sources: 80 | (data['sources'] as List).map((e) => NetDiskSource.fromJson(e)).toList(), 81 | currPage: data['currPage'] as int, 82 | totalPage: data['totalPage'] as int); 83 | } 84 | 85 | toJson() { 86 | return { 87 | 'sources': sources.map((e) => e.toJson()).toList(), 88 | 'currPage': currPage, 89 | 'totalPage': totalPage, 90 | }; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /models/picture_model.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | class Picture { 4 | final String url; 5 | final Map? headers; 6 | final int? width; 7 | final int? height; 8 | final String? size; // 3.5M 9 | final List? tags; 10 | 11 | Picture({ 12 | required this.url, 13 | this.headers, 14 | this.width, 15 | this.height, 16 | this.size, 17 | this.tags, 18 | }); 19 | 20 | static fromJson(Map data) { 21 | return Picture( 22 | url: data['url'] as String, 23 | headers: data['headers']?.map((k, v) => MapEntry(k as String, v as String)) 24 | as Map?, 25 | width: data['width'] as int?, 26 | height: data['height'] as int?, 27 | size: data['size'] as String?, 28 | tags: data['tags']?.map((e) => e.toString()).toList() as List?, 29 | ); 30 | } 31 | 32 | toJson() { 33 | return { 34 | 'url': url, 35 | 'headers': headers, 36 | 'width': width, 37 | 'height': height, 38 | 'size': size, 39 | 'tags': tags, 40 | }; 41 | } 42 | } 43 | 44 | /// 单个相册的属性 45 | class Album { 46 | final String id; 47 | final String? name; 48 | final String? coverUrl; 49 | final Map? coverHeaders; 50 | final List? tags; 51 | final String? title; 52 | final String? description; 53 | final String? creator; 54 | final String? createAt; 55 | final String? detailPageUrl; 56 | late final Map extra; 57 | 58 | Album({ 59 | required this.id, 60 | this.name, 61 | this.coverUrl, 62 | this.coverHeaders, 63 | this.tags, 64 | this.title, 65 | this.description, 66 | this.creator, 67 | this.createAt, 68 | this.detailPageUrl, 69 | extra, 70 | }) { 71 | this.extra = (extra?.map((k, v) => MapEntry(k.toString(), v))) ?? {}; 72 | } 73 | 74 | static fromJson(Map data) { 75 | return Album( 76 | id: data['id'] as String, 77 | name: data['name'] as String?, 78 | coverUrl: data['coverUrl'] as String?, 79 | coverHeaders: 80 | data['coverHeaders']?.map((k, v) => MapEntry(k as String, v as String)) 81 | as Map?, 82 | tags: data['tags']?.map((e) => e.toString()).toList() as List?, 83 | title: data['title'] as String?, 84 | description: data['description'] as String?, 85 | creator: data['creator'] as String?, 86 | createAt: data['createAt'] as String?, 87 | detailPageUrl: data['detailPageUrl'] as String?, 88 | extra: data['extra'], 89 | ); 90 | } 91 | 92 | toJson() { 93 | return { 94 | 'id': id, 95 | 'name': name, 96 | 'coverUrl': coverUrl, 97 | 'coverHeaders': coverHeaders, 98 | 'tags': tags, 99 | 'title': title, 100 | 'description': description, 101 | 'creator': creator, 102 | 'createAt': createAt, 103 | 'detailPageUrl': detailPageUrl, 104 | 'extra': extra, 105 | }; 106 | } 107 | } 108 | 109 | /// 图片的搜索结果 110 | class ResultPictures { 111 | final List pictures; 112 | final int currPage; 113 | final int totalPage; 114 | 115 | ResultPictures({ 116 | required this.pictures, 117 | required this.currPage, 118 | required this.totalPage, 119 | }); 120 | 121 | static fromJson(Map data) { 122 | return ResultPictures( 123 | pictures: (data['pictures'] as List).map((e) => Picture.fromJson(e)).toList(), 124 | currPage: data['currPage'] as int, 125 | totalPage: data['totalPage'] as int, 126 | ); 127 | } 128 | 129 | toJson() { 130 | return { 131 | 'pictures': pictures.map((e) => e.toJson()).toList(), 132 | 'currPage': currPage, 133 | 'totalPage': totalPage, 134 | }; 135 | } 136 | } 137 | 138 | ///相册的搜索结果 139 | class ResultAlbums { 140 | final List albums; 141 | final int currPage; 142 | final int totalPage; 143 | 144 | ResultAlbums({ 145 | required this.albums, 146 | required this.currPage, 147 | required this.totalPage, 148 | }); 149 | 150 | static fromJson(Map data) { 151 | return ResultAlbums( 152 | albums: (data['albums'] as List).map((e) => Album.fromJson(e)).toList(), 153 | currPage: data['currPage'] as int, 154 | totalPage: data['totalPage'] as int, 155 | ); 156 | } 157 | 158 | toJson() { 159 | return { 160 | 'albums': albums.map((e) => e.toJson()).toList(), 161 | 'currPage': currPage, 162 | 'totalPage': totalPage, 163 | }; 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /models/novel_model.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | class Novel { 4 | final String id; 5 | final String name; //书名 6 | final String? author; //作者 7 | final String? coverUrl; //封面地址 8 | final Map? coverHeaders; //封面headers 9 | final String? size; //大小或字数 10 | final DateTime? latestUpdate; //最近更新时间 11 | final List? tags; // 标签 12 | final String? introduce; //介绍 13 | final String? readingChapterId; //正在阅读的章节的id 14 | final DateTime? readingDatetime; // 最新阅读时间 15 | late final Map extra; 16 | 17 | Novel({ 18 | required this.id, 19 | required this.name, 20 | required this.author, 21 | this.coverUrl, 22 | this.coverHeaders, 23 | this.size, 24 | this.latestUpdate, 25 | this.tags, 26 | this.introduce, 27 | this.readingChapterId, 28 | this.readingDatetime, 29 | extra, 30 | }) { 31 | this.extra = (extra?.map((k, v) => MapEntry(k.toString(), v))) ?? {}; 32 | } 33 | 34 | static fromJson(Map data) { 35 | return Novel( 36 | id: data['id'] as String, 37 | name: data['name'] as String, 38 | author: data['author'] as String?, 39 | coverUrl: data['coverUrl'] as String?, 40 | coverHeaders: 41 | data['coverHeaders']?.map((k, v) => MapEntry(k as String, v as String)) 42 | as Map?, 43 | size: data['size'] as String?, 44 | latestUpdate: data['latestUpdate'] == null ? null : DateTime.tryParse(data['latestUpdate']), 45 | tags: data['tags']?.map((e) => e.toString()).toList() as List?, 46 | introduce: data['introduce'] as String?, 47 | readingChapterId: data['readingChapterId'] as String?, 48 | readingDatetime: 49 | data['readingDatetime'] == null ? null : DateTime.tryParse(data['readingDatetime']), 50 | extra: data['extra'], 51 | ); 52 | } 53 | 54 | toJson() { 55 | return { 56 | "id": id, 57 | "name": name, 58 | "author": author, 59 | "coverUrl": coverUrl, 60 | "coverHeaders": coverHeaders, 61 | "size": size, 62 | "latestUpdate": latestUpdate != null ? latestUpdate.toString() : latestUpdate, 63 | "tags": tags, 64 | "introduce": introduce, 65 | "readingChapterId": readingChapterId, 66 | "readingDatetime": readingDatetime != null ? readingDatetime.toString() : readingDatetime, 67 | "extra": extra, 68 | }; 69 | } 70 | } 71 | 72 | /// 小说的搜索结果 73 | class ResultNovels { 74 | final List novels; 75 | final int currPage; 76 | final int totalPage; 77 | 78 | ResultNovels({ 79 | required this.novels, 80 | required this.currPage, 81 | required this.totalPage, 82 | }); 83 | 84 | static fromJson(Map data) { 85 | return ResultNovels( 86 | novels: (data['novels'] as List).map((e) => Novel.fromJson(e)).toList(), 87 | currPage: data['currPage'] as int, 88 | totalPage: data['totalPage'] as int); 89 | } 90 | 91 | toJson() { 92 | return { 93 | 'novels': novels.map((e) => e.toJson()).toList(), 94 | 'currPage': currPage, 95 | 'totalPage': totalPage, 96 | }; 97 | } 98 | } 99 | 100 | class NovelChapter { 101 | final String id; 102 | final String chapterName; 103 | final String? chapterUrl; 104 | late final Map extra; 105 | 106 | NovelChapter({ 107 | required this.id, 108 | required this.chapterName, 109 | this.chapterUrl, 110 | extra, 111 | }) { 112 | this.extra = (extra?.map((k, v) => MapEntry(k.toString(), v))) ?? {}; 113 | } 114 | 115 | static fromJson(Map data) { 116 | return NovelChapter( 117 | id: data['id'] as String, 118 | chapterName: data['chapterName'] as String, 119 | chapterUrl: data['chapterUrl'] as String?, 120 | extra: data['extra'], 121 | ); 122 | } 123 | 124 | toJson() { 125 | return { 126 | 'id': id, 127 | 'chapterName': chapterName, 128 | 'chapterUrl': chapterUrl, 129 | 'extra': extra, 130 | }; 131 | } 132 | } 133 | 134 | class ResultChapters { 135 | final List chapters; 136 | final String? introduce; 137 | final String? author; 138 | final DateTime? latestUpdate; //最近更新时间 139 | final List? tags; // 标签 140 | final String? size; //大小或字数 141 | late final Map extra; 142 | 143 | ResultChapters({ 144 | required this.chapters, 145 | this.introduce, 146 | this.author, 147 | this.latestUpdate, 148 | this.tags, 149 | this.size, 150 | extra, 151 | }) { 152 | this.extra = (extra?.map((k, v) => MapEntry(k.toString(), v))) ?? {}; 153 | } 154 | 155 | static fromJson(Map data) { 156 | return ResultChapters( 157 | chapters: 158 | (data['chapters'] as List).map((e) => NovelChapter.fromJson(e)).toList(), 159 | introduce: data['introduce'] as String?, 160 | author: data['author'] as String?, 161 | latestUpdate: data['latestUpdate'] == null ? null : DateTime.tryParse(data['latestUpdate']), 162 | //最近更新时间 163 | tags: data['tags']?.map((e) => e.toString()).toList() as List?, 164 | // 标签 165 | size: data['size'] as String?, 166 | //大小或字数 167 | extra: data['extra'], 168 | ); 169 | } 170 | 171 | toJson() { 172 | return { 173 | 'chapters': chapters.map((e) => e.toJson()).toList(), 174 | 'introduce': introduce, 175 | 'author': author, 176 | 'latestUpdate': latestUpdate, 177 | 'tags': tags, 178 | 'size': size, 179 | 'extra': extra, 180 | }; 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /models/video_model.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | class Video { 4 | final String id; // 唯一标识 5 | final String videoName; // 名称 6 | final String? coverUrl; //封面url 7 | final Map? coverHeaders; //封面headers 8 | final String? detailPageUrl; 9 | final String? actors; // 演员 10 | final String? introduce; //介绍 11 | final List? tags; // 类型列表 12 | final DateTime? latestUpdate; //最新更新时间 13 | late final Map extra; 14 | 15 | Video({ 16 | required this.id, 17 | required this.videoName, 18 | this.coverUrl, 19 | this.coverHeaders, 20 | this.detailPageUrl, 21 | this.actors, 22 | this.introduce, 23 | this.tags, 24 | this.latestUpdate, 25 | extra, 26 | }) { 27 | this.extra = (extra?.map((k, v) => MapEntry(k.toString(), v))) ?? {}; 28 | } 29 | 30 | static fromJson(Map data) { 31 | return Video( 32 | id: data['id'] as String, 33 | videoName: data['videoName'] as String, 34 | coverUrl: data['coverUrl'] as String?, 35 | coverHeaders: data['coverHeaders']?.map((k, v) { 36 | return MapEntry(k as String, v as String); 37 | }) as Map?, 38 | detailPageUrl: data['detailPageUrl'] as String?, 39 | actors: data['actors'] as String?, 40 | introduce: data['introduce'] as String?, 41 | tags: data['tags']?.map((e) => e.toString()).toList() as List?, 42 | latestUpdate: data['latestUpdate'] == null ? null : DateTime.tryParse(data['latestUpdate']), 43 | extra: data['extra'], 44 | ); 45 | } 46 | 47 | toJson() { 48 | return { 49 | "id": id, 50 | "videoName": videoName, 51 | "coverUrl": coverUrl, 52 | "coverHeaders": coverHeaders, 53 | 'detailPageUrl': detailPageUrl, 54 | "actors": actors, 55 | "introduce": introduce, 56 | "tags": tags, 57 | "latestUpdate": latestUpdate != null ? latestUpdate.toString() : latestUpdate, 58 | "extra": extra, 59 | }; 60 | } 61 | } 62 | 63 | class ResultVideos { 64 | final List