├── .github └── workflows │ ├── APK-J-Jar.yml │ ├── APK-J.yml │ ├── APK-T-Jar.yml │ └── APK-T.yml ├── DIY ├── J │ ├── ApiConfig.java │ ├── App.java │ ├── DetailActivity.java │ ├── HomeActivity.java │ ├── LivePlayActivity.java │ ├── VodController.java │ ├── activity_home.xml │ ├── activity_live_play.xml │ ├── fragment_user.xml │ └── player_vod_control_view.xml ├── T │ ├── ApiConfig.java │ ├── App.java │ ├── BaseActivity.java │ ├── HomeActivity.java │ ├── HomeIconDialog.java │ ├── LivePlayActivity.java │ ├── SearchActivity.java │ ├── UserFragment.java │ ├── VodController.java │ ├── activity_home.xml │ └── fragment_user.xml ├── TVBoxOSC.jks ├── app_bg.png ├── app_bg_black.png ├── app_icon.png └── bg.jpg ├── LICENSE ├── README.md ├── diy-J-Jar.sh ├── diy-J.sh ├── diy-T-Jar.sh └── diy-T.sh /.github/workflows/APK-J-Jar.yml: -------------------------------------------------------------------------------- 1 | name: APK-J-Jar Build 2 | 3 | on: 4 | # push: 5 | # branches: 6 | # - main 7 | # pull_request: 8 | workflow_dispatch: 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | with: 16 | fetch-depth: 0 17 | - name: Clone Project 18 | run: git clone -b main --depth=1 https://github.com/zhoujck/TVBoxOS 19 | - name: DIY 20 | run: | 21 | chmod +x diy-J-Jar.sh 22 | bash ${{ github.workspace }}/diy-J-Jar.sh 23 | - name: Build With Gradle 24 | run: | 25 | num=$(find ${{ github.workspace }} -name gradlew | awk -F"/" '{print NF-1}') 26 | DIR=$(find ${{ github.workspace }} -name gradlew | cut -d \/ -f$num) 27 | cd $DIR 28 | chmod +x gradlew 29 | ./gradlew assemblerelease --build-cache --parallel --daemon --warning-mode all 30 | - name: Prepare App 31 | run: | 32 | mkdir -p ${{ github.workspace }}/apk/ 33 | for file in `find ~ -name "*.apk" -print`; do 34 | mv "$file" ${{ github.workspace }}/apk/ 35 | done 36 | - name: Upload App To Artifact 37 | uses: actions/upload-artifact@v3 38 | with: 39 | name: 糖果 40 | path: ${{ github.workspace }}/apk/* 41 | -------------------------------------------------------------------------------- /.github/workflows/APK-J.yml: -------------------------------------------------------------------------------- 1 | name: APK-J Build 2 | 3 | on: 4 | # push: 5 | # branches: 6 | # - main 7 | # pull_request: 8 | workflow_dispatch: 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | with: 16 | fetch-depth: 0 17 | - name: Clone Project 18 | run: git clone -b main --depth=1 https://github.com/zhoujck/TVBoxOS 19 | - name: DIY 20 | run: | 21 | chmod +x diy-J.sh 22 | bash ${{ github.workspace }}/diy-J.sh 23 | - name: Build With Gradle 24 | run: | 25 | num=$(find ${{ github.workspace }} -name gradlew | awk -F"/" '{print NF-1}') 26 | DIR=$(find ${{ github.workspace }} -name gradlew | cut -d \/ -f$num) 27 | cd $DIR 28 | chmod +x gradlew 29 | ./gradlew assemblerelease --build-cache --parallel --daemon --warning-mode all 30 | - name: Prepare App 31 | run: | 32 | mkdir -p ${{ github.workspace }}/apk/ 33 | for file in `find ~ -name "*.apk" -print`; do 34 | mv "$file" ${{ github.workspace }}/apk/ 35 | done 36 | - name: Upload App To Artifact 37 | uses: actions/upload-artifact@v3 38 | with: 39 | name: 糖果 40 | path: ${{ github.workspace }}/apk/* 41 | -------------------------------------------------------------------------------- /.github/workflows/APK-T-Jar.yml: -------------------------------------------------------------------------------- 1 | 2 | name: APK-T-Jar Build 3 | 4 | on: 5 | # push: 6 | # branches: 7 | # - main 8 | # pull_request: 9 | workflow_dispatch: 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v3 17 | with: 18 | fetch-depth: 0 19 | - name: set up JDK 17 20 | uses: actions/setup-java@v2 21 | with: 22 | java-version: '17' 23 | distribution: 'adopt' 24 | # - uses: actions/checkout@v3 25 | # with: 26 | # fetch-depth: 0 27 | - name: Clone Project 28 | run: git clone -b main --depth=1 https://github.com/takagen99/Box 29 | - name: DIY 30 | run: | 31 | chmod +x diy-T-Jar.sh 32 | bash ${{ github.workspace }}/diy-T-Jar.sh 33 | - name: Build With Gradle 34 | run: | 35 | num=$(find ${{ github.workspace }} -name gradlew | awk -F"/" '{print NF-1}') 36 | DIR=$(find ${{ github.workspace }} -name gradlew | cut -d \/ -f$num) 37 | cd $DIR 38 | chmod +x gradlew 39 | ./gradlew assemblerelease --build-cache --parallel --daemon --warning-mode all 40 | 41 | - name: Prepare App 42 | run: | 43 | mkdir -p ${{ github.workspace }}/apk/ 44 | for file in `find ~ -name "*.apk" -print`; do 45 | mv "$file" ${{ github.workspace }}/apk/ 46 | done 47 | - name: Upload App To Artifact 48 | uses: actions/upload-artifact@v3 49 | with: 50 | name: 糖果 51 | path: ${{ github.workspace }}/apk/* 52 | -------------------------------------------------------------------------------- /.github/workflows/APK-T.yml: -------------------------------------------------------------------------------- 1 | name: APK-T Build 2 | 3 | on: 4 | # push: 5 | # branches: 6 | # - main 7 | # pull_request: 8 | workflow_dispatch: 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | with: 16 | fetch-depth: 0 17 | - name: Clone Project 18 | run: git clone -b main --depth=1 https://github.com/zhoujck/takagen99.git 19 | - name: DIY 20 | run: | 21 | chmod +x diy-T.sh 22 | bash ${{ github.workspace }}/diy-T.sh 23 | - name: Build With Gradle 24 | run: | 25 | num=$(find ${{ github.workspace }} -name gradlew | awk -F"/" '{print NF-1}') 26 | DIR=$(find ${{ github.workspace }} -name gradlew | cut -d \/ -f$num) 27 | cd $DIR 28 | chmod +x gradlew 29 | ./gradlew assemblerelease --build-cache --parallel --daemon --warning-mode all 30 | - name: Prepare App 31 | run: | 32 | mkdir -p ${{ github.workspace }}/apk/ 33 | for file in `find ~ -name "*.apk" -print`; do 34 | mv "$file" ${{ github.workspace }}/apk/ 35 | done 36 | - name: Upload App To Artifact 37 | uses: actions/upload-artifact@v3 38 | with: 39 | name: 糖果tv 40 | path: ${{ github.workspace }}/apk/* 41 | -------------------------------------------------------------------------------- /DIY/J/App.java: -------------------------------------------------------------------------------- 1 | package com.github.tvbox.osc.base; 2 | 3 | import android.app.Activity; 4 | import androidx.multidex.MultiDexApplication; 5 | 6 | import com.github.tvbox.osc.bean.VodInfo; 7 | import com.github.tvbox.osc.callback.EmptyCallback; 8 | import com.github.tvbox.osc.callback.LoadingCallback; 9 | import com.github.tvbox.osc.data.AppDataManager; 10 | import com.github.tvbox.osc.server.ControlManager; 11 | import com.github.tvbox.osc.util.AppManager; 12 | import com.github.tvbox.osc.util.EpgUtil; 13 | import com.github.tvbox.osc.util.FileUtils; 14 | import com.github.tvbox.osc.util.HawkConfig; 15 | import com.github.tvbox.osc.util.OkGoHelper; 16 | import com.github.tvbox.osc.util.PlayerHelper; 17 | import com.github.tvbox.osc.util.js.JSEngine; 18 | import com.kingja.loadsir.core.LoadSir; 19 | import com.orhanobut.hawk.Hawk; 20 | 21 | import me.jessyan.autosize.AutoSizeConfig; 22 | import me.jessyan.autosize.unit.Subunits; 23 | 24 | /** 25 | * @author pj567 26 | * @date :2020/12/17 27 | * @description: 28 | */ 29 | public class App extends MultiDexApplication { 30 | private static App instance; 31 | 32 | @Override 33 | public void onCreate() { 34 | super.onCreate(); 35 | instance = this; 36 | initParams(); 37 | // OKGo 38 | OkGoHelper.init(); //台标获取 39 | EpgUtil.init(); 40 | // 初始化Web服务器 41 | ControlManager.init(this); 42 | //初始化数据库 43 | AppDataManager.init(); 44 | LoadSir.beginBuilder() 45 | .addCallback(new EmptyCallback()) 46 | .addCallback(new LoadingCallback()) 47 | .commit(); 48 | AutoSizeConfig.getInstance().setCustomFragment(true).getUnitsManager() 49 | .setSupportDP(false) 50 | .setSupportSP(false) 51 | .setSupportSubunits(Subunits.MM); 52 | PlayerHelper.init(); 53 | JSEngine.getInstance().create(); 54 | FileUtils.cleanPlayerCache(); 55 | } 56 | 57 | private void initParams() { 58 | // Hawk 59 | Hawk.init(this).build(); 60 | Hawk.put(HawkConfig.DEBUG_OPEN, false); 61 | putDefault(HawkConfig.HOME_REC, 0); // Home Rec 0=豆瓣, 1=站点推荐, 2=历史 62 | putDefault(HawkConfig.HOME_REC_STYLE, true); // 首页多行 是 or 否 63 | putDefault(HawkConfig.FAST_SEARCH_MODE, false); // 聚合模式 打开 or 关闭 64 | putDefault(HawkConfig.PLAY_TYPE, 1); // Player 0=系统, 1=IJK, 2=Exo 65 | putDefault(HawkConfig.IJK_CODEC, "硬解码");// IJK Render 软解码, 硬解码 66 | putDefault(HawkConfig.DOH_URL, 2); // DNS 0=关闭 1=腾讯 2=阿里 3=360 67 | putDefault(HawkConfig.SEARCH_VIEW, 1); // 搜索展示 Text or Picture 68 | putDefault(HawkConfig.IJK_CACHE_PLAY, true); // IJK缓存 打开 or 关闭 69 | putDefault(HawkConfig.HISTORY_NUM, 0); // 0=30 1=50 2=70 70 | } 71 | 72 | public static App getInstance() { 73 | return instance; 74 | } 75 | 76 | @Override 77 | public void onTerminate() { 78 | super.onTerminate(); 79 | JSEngine.getInstance().destroy(); 80 | } 81 | 82 | 83 | private VodInfo vodInfo; 84 | public void setVodInfo(VodInfo vodinfo){ 85 | this.vodInfo = vodinfo; 86 | } 87 | public VodInfo getVodInfo(){ 88 | return this.vodInfo; 89 | } 90 | 91 | public Activity getCurrentActivity() { 92 | return AppManager.getInstance().currentActivity(); 93 | } 94 | private void putDefault(String key, Object value) { 95 | if (!Hawk.contains(key)) { 96 | Hawk.put(key, value); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /DIY/J/activity_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 21 | 22 | 34 | 35 | 48 | 49 | 60 | 61 | 62 | 73 | 74 | 83 | 84 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /DIY/J/activity_live_play.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 26 | 34 | 40 | 41 | 42 | 43 | 44 | 57 | 62 | 63 | 71 | 88 | 89 | 96 | 97 | 98 | 99 | 100 | 109 | 110 | 118 | 119 | 124 | 125 | 134 | 135 | 136 | 137 | 138 | 148 | 149 | 162 | 163 | 172 | 173 | 186 | 187 | 188 | 193 | 194 | 204 | 205 | 210 | 211 | 219 | 220 | 233 | 234 | 244 | 245 | 258 | 259 | 266 | 267 | 280 | 291 | 292 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 320 | 321 | 333 | 334 | 339 | 340 | 352 | 353 | 354 | 369 | 370 | 383 | 384 | 397 | 398 | 399 | 400 | 407 | 414 | 415 | 425 | 448 | 458 | 463 | 464 | 476 | 483 | 484 | 485 | 508 | 509 | 510 | 522 | 533 | 534 | 553 | 561 | 572 | 583 | 584 | 603 | 604 | 616 | 617 | 629 | 630 | 631 | 632 | 639 | 640 | 641 | 648 | 649 | 650 | 656 | 657 | 658 | 669 | 678 | 679 | 699 | 700 | 724 | 725 | 726 | 727 | 728 | 729 | 740 | 749 | 757 | 758 | 774 | 775 | 791 | 792 | 793 | 794 | 795 | -------------------------------------------------------------------------------- /DIY/J/fragment_user.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 22 | 23 | 38 | 39 | 40 | 46 | 47 | 59 | 60 | 61 | 62 | 77 | 78 | 79 | 85 | 86 | 98 | 99 | 100 | 101 | 116 | 117 | 118 | 124 | 125 | 137 | 138 | 139 | 140 | 141 | 157 | 158 | 159 | 165 | 166 | 178 | 179 | 180 | 181 | 196 | 197 | 198 | 204 | 205 | 217 | 218 | 219 | 220 | 221 | 236 | 237 | 238 | 244 | 245 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 282 | 283 | 300 | 301 | 302 | 303 | -------------------------------------------------------------------------------- /DIY/J/player_vod_control_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 21 | 22 | 35 | 36 | 48 | 49 | 50 | 51 | 63 | 64 | 77 | 78 | 92 | 93 | 94 | 106 | 107 | 108 | 109 | 123 | 124 | 138 | 139 | 144 | 157 | 171 | 172 | 185 | 186 | 199 | 200 | 214 | 215 | 228 | 229 | 242 | 243 | 256 | 257 | 270 | 271 | 284 | 285 | 286 | 287 | 300 | 301 | 313 | 314 | 327 | 328 | 341 | 342 | 343 | 355 | 356 | 369 | 370 | 383 | 384 | 396 | 397 | 398 | 399 | 407 | 408 | 418 | 419 | 428 | 429 | 430 | 431 | 436 | 437 | 446 | 447 | 465 | 466 | 475 | 476 | 477 | 478 | 479 | 480 | 487 | 488 | 496 | 497 | 509 | 510 | 511 | 520 | 521 | 528 | 529 | 541 | 542 | 543 | 544 | 545 | 560 | 561 | 573 | 574 | 581 | 582 | 593 | 594 | 595 | 596 | 605 | 606 | 618 | 619 | 620 | -------------------------------------------------------------------------------- /DIY/T/App.java: -------------------------------------------------------------------------------- 1 | package com.github.tvbox.osc.base; 2 | 3 | import androidx.multidex.MultiDexApplication; 4 | 5 | import com.github.tvbox.osc.callback.EmptyCallback; 6 | import com.github.tvbox.osc.callback.LoadingCallback; 7 | import com.github.tvbox.osc.data.AppDataManager; 8 | import com.github.tvbox.osc.server.ControlManager; 9 | import com.github.tvbox.osc.util.EpgUtil; 10 | import com.github.tvbox.osc.util.FileUtils; 11 | import com.github.tvbox.osc.util.HawkConfig; 12 | import com.github.tvbox.osc.util.LocaleHelper; 13 | import com.github.tvbox.osc.util.OkGoHelper; 14 | import com.github.tvbox.osc.util.PlayerHelper; 15 | import com.github.tvbox.osc.util.js.JSEngine; 16 | import com.kingja.loadsir.core.LoadSir; 17 | import com.orhanobut.hawk.Hawk; 18 | 19 | import java.io.File; 20 | 21 | import me.jessyan.autosize.AutoSizeConfig; 22 | import me.jessyan.autosize.unit.Subunits; 23 | 24 | /** 25 | * @author pj567 26 | * @date :2020/12/17 27 | * @description: 28 | */ 29 | public class App extends MultiDexApplication { 30 | private static App instance; 31 | 32 | @Override 33 | public void onCreate() { 34 | super.onCreate(); 35 | instance = this; 36 | initParams(); 37 | // takagen99 : Initialize Locale 38 | initLocale(); 39 | // OKGo 40 | OkGoHelper.init(); 41 | // Get EPG Info 42 | EpgUtil.init(); 43 | // 初始化Web服务器 44 | ControlManager.init(this); 45 | //初始化数据库 46 | AppDataManager.init(); 47 | LoadSir.beginBuilder() 48 | .addCallback(new EmptyCallback()) 49 | .addCallback(new LoadingCallback()) 50 | .commit(); 51 | AutoSizeConfig.getInstance().setCustomFragment(true).getUnitsManager() 52 | .setSupportDP(false) 53 | .setSupportSP(false) 54 | .setSupportSubunits(Subunits.MM); 55 | PlayerHelper.init(); 56 | 57 | // Delete Cache 58 | File dir = getCacheDir(); 59 | FileUtils.recursiveDelete(dir); 60 | dir = getExternalCacheDir(); 61 | FileUtils.recursiveDelete(dir); 62 | 63 | // Add JS support 64 | JSEngine.getInstance().create(); 65 | } 66 | 67 | private void initParams() { 68 | // Hawk 69 | Hawk.init(this).build(); 70 | Hawk.put(HawkConfig.DEBUG_OPEN, false); 71 | 72 | putDefault(HawkConfig.HOME_REC, 0); // Home Rec 0=豆瓣, 1=推荐, 2=历史 73 | putDefault(HawkConfig.PLAY_TYPE, 1); // Player 0=系统, 1=IJK, 2=Exo 74 | putDefault(HawkConfig.IJK_CODEC, "硬解码");// IJK Render 软解码, 硬解码 75 | putDefault(HawkConfig.HOME_SEARCH_POSITION, false);// 上方/下方 76 | putDefault(HawkConfig.HOME_MENU_POSITION, false);// 上方/下方 77 | putDefault(HawkConfig.HOME_SHOW_SOURCE, true);// 开启/关闭 78 | putDefault(HawkConfig.HOME_REC_STYLE, true);// 开启/关闭 79 | putDefault(HawkConfig.HOME_NUM, 0); // 0=30 1=50 2=70 80 | 81 | 82 | } 83 | 84 | private void initLocale() { 85 | if (Hawk.get(HawkConfig.HOME_LOCALE, 0) == 0) { 86 | LocaleHelper.setLocale(App.this, "zh"); 87 | } else { 88 | LocaleHelper.setLocale(App.this, ""); 89 | } 90 | } 91 | 92 | public static App getInstance() { 93 | return instance; 94 | } 95 | 96 | private void putDefault(String key, Object value) { 97 | if (!Hawk.contains(key)) { 98 | Hawk.put(key, value); 99 | } 100 | } 101 | 102 | @Override 103 | public void onTerminate() { 104 | super.onTerminate(); 105 | JSEngine.getInstance().destroy(); 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /DIY/T/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.github.tvbox.osc.base; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.content.res.AssetManager; 6 | import android.content.res.Resources; 7 | import android.content.res.TypedArray; 8 | import android.graphics.BitmapFactory; 9 | import android.graphics.drawable.BitmapDrawable; 10 | import android.os.Build; 11 | import android.os.Bundle; 12 | import android.os.Looper; 13 | import android.util.DisplayMetrics; 14 | import android.view.View; 15 | import android.view.WindowManager; 16 | 17 | import androidx.annotation.Nullable; 18 | import androidx.appcompat.app.AppCompatActivity; 19 | import androidx.core.content.PermissionChecker; 20 | 21 | import com.github.tvbox.osc.R; 22 | import com.github.tvbox.osc.callback.EmptyCallback; 23 | import com.github.tvbox.osc.callback.LoadingCallback; 24 | import com.github.tvbox.osc.util.AppManager; 25 | import com.github.tvbox.osc.util.HawkConfig; 26 | import com.github.tvbox.osc.util.LocaleHelper; 27 | import com.kingja.loadsir.callback.Callback; 28 | import com.kingja.loadsir.core.LoadService; 29 | import com.kingja.loadsir.core.LoadSir; 30 | import com.orhanobut.hawk.Hawk; 31 | 32 | import java.io.BufferedReader; 33 | import java.io.File; 34 | import java.io.IOException; 35 | import java.io.InputStreamReader; 36 | 37 | import me.jessyan.autosize.AutoSizeCompat; 38 | import me.jessyan.autosize.internal.CustomAdapt; 39 | import xyz.doikki.videoplayer.util.CutoutUtil; 40 | 41 | /** 42 | * @author pj567 43 | * @date :2020/12/17 44 | * @description: 45 | */ 46 | public abstract class BaseActivity extends AppCompatActivity implements CustomAdapt { 47 | protected Context mContext; 48 | private LoadService mLoadService; 49 | 50 | private static float screenRatio = -100.0f; 51 | 52 | // takagen99 : Fix for Locale change not persist on higher Android version 53 | @Override 54 | protected void attachBaseContext(Context base) { 55 | if (Hawk.get(HawkConfig.HOME_LOCALE, 0) == 0) { 56 | super.attachBaseContext(LocaleHelper.onAttach(base, "zh")); 57 | } else { 58 | super.attachBaseContext(LocaleHelper.onAttach(base, "")); 59 | } 60 | } 61 | 62 | @Override 63 | protected void onCreate(@Nullable Bundle savedInstanceState) { 64 | try { 65 | if (screenRatio < 0) { 66 | DisplayMetrics dm = new DisplayMetrics(); 67 | getWindowManager().getDefaultDisplay().getMetrics(dm); 68 | int screenWidth = dm.widthPixels; 69 | int screenHeight = dm.heightPixels; 70 | screenRatio = (float) Math.max(screenWidth, screenHeight) / (float) Math.min(screenWidth, screenHeight); 71 | } 72 | } catch (Throwable th) { 73 | th.printStackTrace(); 74 | } 75 | 76 | // takagen99 : Set Theme Color 77 | if (Hawk.get(HawkConfig.THEME_SELECT, 0) == 0) { 78 | setTheme(R.style.NetfxTheme); 79 | } else if (Hawk.get(HawkConfig.THEME_SELECT, 0) == 1) { 80 | setTheme(R.style.DoraeTheme); 81 | } else if (Hawk.get(HawkConfig.THEME_SELECT, 0) == 2) { 82 | setTheme(R.style.PepsiTheme); 83 | } else if (Hawk.get(HawkConfig.THEME_SELECT, 0) == 3) { 84 | setTheme(R.style.NarutoTheme); 85 | } else if (Hawk.get(HawkConfig.THEME_SELECT, 0) == 4) { 86 | setTheme(R.style.MinionTheme); 87 | } else if (Hawk.get(HawkConfig.THEME_SELECT, 0) == 5) { 88 | setTheme(R.style.YagamiTheme); 89 | } else { 90 | setTheme(R.style.SakuraTheme); 91 | } 92 | 93 | super.onCreate(savedInstanceState); 94 | setContentView(getLayoutResID()); 95 | mContext = this; 96 | CutoutUtil.adaptCutoutAboveAndroidP(mContext, true);//设置刘海 97 | AppManager.getInstance().addActivity(this); 98 | init(); 99 | setScreenOn(); 100 | } 101 | 102 | @Override 103 | protected void onResume() { 104 | super.onResume(); 105 | hideSystemUI(true); 106 | changeWallpaper(false); 107 | } 108 | 109 | // takagen99 : Check for Gesture or 3-Buttons NavBar 110 | // 0 : 3-Button NavBar 111 | // 1 : 2-Button NavBar (Android P) 112 | // 2 : Gesture full screen 113 | public static int isEdgeToEdgeEnabled(Context context) { 114 | Resources resources = context.getResources(); 115 | int resourceId = resources.getIdentifier("config_navBarInteractionMode", "integer", "android"); 116 | if (resourceId > 0) { 117 | return resources.getInteger(resourceId); 118 | } 119 | return 0; 120 | } 121 | 122 | public void hideSysBar() { 123 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 124 | int uiOptions = getWindow().getDecorView().getSystemUiVisibility(); 125 | uiOptions |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE; 126 | uiOptions |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; 127 | uiOptions |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 128 | uiOptions |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; 129 | uiOptions |= View.SYSTEM_UI_FLAG_FULLSCREEN; 130 | uiOptions |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; 131 | getWindow().getDecorView().setSystemUiVisibility(uiOptions); 132 | } 133 | } 134 | 135 | public void vidHideSysBar() { 136 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 137 | int uiOptions = getWindow().getDecorView().getSystemUiVisibility(); 138 | uiOptions |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE; 139 | uiOptions |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; 140 | uiOptions |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 141 | uiOptions |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; 142 | uiOptions |= View.SYSTEM_UI_FLAG_FULLSCREEN; 143 | uiOptions |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; 144 | getWindow().getDecorView().setSystemUiVisibility(uiOptions); 145 | } 146 | } 147 | 148 | public void hideSystemUI(boolean shownavbar) { 149 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 150 | int uiVisibility = getWindow().getDecorView().getSystemUiVisibility(); 151 | uiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE; 152 | uiVisibility |= View.SYSTEM_UI_FLAG_LOW_PROFILE; 153 | uiVisibility |= View.SYSTEM_UI_FLAG_FULLSCREEN; 154 | uiVisibility |= View.SYSTEM_UI_FLAG_IMMERSIVE; 155 | uiVisibility |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; 156 | if (!shownavbar) { 157 | uiVisibility |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; 158 | uiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; 159 | } 160 | getWindow().getDecorView().setSystemUiVisibility(uiVisibility); 161 | // set content behind navigation bar 162 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); 163 | } 164 | } 165 | 166 | public void showSystemUI() { 167 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 168 | int uiVisibility = getWindow().getDecorView().getSystemUiVisibility(); 169 | uiVisibility &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE; 170 | uiVisibility &= ~View.SYSTEM_UI_FLAG_FULLSCREEN; 171 | uiVisibility &= ~View.SYSTEM_UI_FLAG_IMMERSIVE; 172 | uiVisibility &= ~View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; 173 | uiVisibility &= ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; 174 | uiVisibility &= ~View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; 175 | getWindow().getDecorView().setSystemUiVisibility(uiVisibility); 176 | } 177 | } 178 | 179 | @Override 180 | public Resources getResources() { 181 | if (Looper.myLooper() == Looper.getMainLooper()) { 182 | AutoSizeCompat.autoConvertDensityOfCustomAdapt(super.getResources(), this); 183 | } 184 | return super.getResources(); 185 | } 186 | 187 | public boolean hasPermission(String permission) { 188 | boolean has = true; 189 | try { 190 | has = PermissionChecker.checkSelfPermission(this, permission) == PermissionChecker.PERMISSION_GRANTED; 191 | } catch (Exception e) { 192 | e.printStackTrace(); 193 | } 194 | return has; 195 | } 196 | 197 | protected abstract int getLayoutResID(); 198 | 199 | protected abstract void init(); 200 | 201 | protected void setLoadSir(View view) { 202 | if (mLoadService == null) { 203 | mLoadService = LoadSir.getDefault().register(view, new Callback.OnReloadListener() { 204 | @Override 205 | public void onReload(View v) { 206 | } 207 | }); 208 | } 209 | } 210 | 211 | protected void showLoading() { 212 | if (mLoadService != null) { 213 | mLoadService.showCallback(LoadingCallback.class); 214 | } 215 | } 216 | 217 | protected void showEmpty() { 218 | if (null != mLoadService) { 219 | mLoadService.showCallback(EmptyCallback.class); 220 | } 221 | } 222 | 223 | protected void showSuccess() { 224 | if (null != mLoadService) { 225 | mLoadService.showSuccess(); 226 | } 227 | } 228 | 229 | @Override 230 | protected void onDestroy() { 231 | super.onDestroy(); 232 | AppManager.getInstance().finishActivity(this); 233 | } 234 | 235 | public void jumpActivity(Class clazz) { 236 | Intent intent = new Intent(mContext, clazz); 237 | startActivity(intent); 238 | } 239 | 240 | public void jumpActivity(Class clazz, Bundle bundle) { 241 | Intent intent = new Intent(mContext, clazz); 242 | intent.putExtras(bundle); 243 | startActivity(intent); 244 | } 245 | 246 | protected String getAssetText(String fileName) { 247 | StringBuilder stringBuilder = new StringBuilder(); 248 | try { 249 | AssetManager assets = getAssets(); 250 | BufferedReader bf = new BufferedReader(new InputStreamReader(assets.open(fileName))); 251 | String line; 252 | while ((line = bf.readLine()) != null) { 253 | stringBuilder.append(line); 254 | } 255 | return stringBuilder.toString(); 256 | } catch (IOException e) { 257 | e.printStackTrace(); 258 | } 259 | return ""; 260 | } 261 | 262 | @Override 263 | public float getSizeInDp() { 264 | return isBaseOnWidth() ? 1280 : 720; 265 | } 266 | 267 | @Override 268 | public boolean isBaseOnWidth() { 269 | return !(screenRatio >= 4.0f); 270 | } 271 | 272 | public boolean supportsPiPMode() { 273 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O; 274 | } 275 | 276 | public boolean supportsTouch() { 277 | return getPackageManager().hasSystemFeature("android.hardware.touchscreen"); 278 | } 279 | 280 | public void setScreenBrightness(float amt) { 281 | WindowManager.LayoutParams lparams = getWindow().getAttributes(); 282 | lparams.screenBrightness = amt; 283 | getWindow().setAttributes(lparams); 284 | } 285 | 286 | public void setScreenOn() { 287 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 288 | } 289 | 290 | public void setScreenOff() { 291 | getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 292 | } 293 | 294 | // takagen99: Added Theme Color 295 | public int getThemeColor() { 296 | TypedArray a = mContext.obtainStyledAttributes(R.styleable.themeColor); 297 | int themeColor = a.getColor(R.styleable.themeColor_color_theme, 0); 298 | return themeColor; 299 | } 300 | 301 | protected static BitmapDrawable globalWp = null; 302 | 303 | public void changeWallpaper(boolean force) { 304 | if (!force && globalWp != null) { 305 | getWindow().setBackgroundDrawable(globalWp); 306 | return; 307 | } 308 | try { 309 | File wp = new File(getFilesDir().getAbsolutePath() + "/wp"); 310 | if (wp.exists()) { 311 | BitmapFactory.Options opts = new BitmapFactory.Options(); 312 | opts.inJustDecodeBounds = true; 313 | BitmapFactory.decodeFile(wp.getAbsolutePath(), opts); 314 | // 从Options中获取图片的分辨率 315 | int imageHeight = opts.outHeight; 316 | int imageWidth = opts.outWidth; 317 | int picHeight = 720; 318 | int picWidth = 1080; 319 | int scaleX = imageWidth / picWidth; 320 | int scaleY = imageHeight / picHeight; 321 | int scale = Math.max(Math.max(scaleX, scaleY), 1); 322 | opts.inJustDecodeBounds = false; 323 | // 采样率 324 | opts.inSampleSize = scale; 325 | globalWp = new BitmapDrawable(BitmapFactory.decodeFile(wp.getAbsolutePath(), opts)); 326 | } else { 327 | globalWp = null; 328 | } 329 | } catch (Throwable throwable) { 330 | throwable.printStackTrace(); 331 | globalWp = null; 332 | } 333 | if (globalWp != null) { 334 | getWindow().setBackgroundDrawable(globalWp); 335 | } else { 336 | getWindow().setBackgroundDrawableResource(R.drawable.app_bg); 337 | } 338 | } 339 | } 340 | -------------------------------------------------------------------------------- /DIY/T/HomeIconDialog.java: -------------------------------------------------------------------------------- 1 | package com.github.tvbox.osc.ui.dialog; 2 | 3 | import android.content.Context; 4 | import android.view.View; 5 | import android.widget.TextView; 6 | 7 | import androidx.annotation.NonNull; 8 | 9 | import com.github.tvbox.osc.R; 10 | import com.github.tvbox.osc.util.FastClickCheckUtil; 11 | import com.github.tvbox.osc.util.HawkConfig; 12 | import com.orhanobut.hawk.Hawk; 13 | 14 | import org.jetbrains.annotations.NotNull; 15 | 16 | /** 17 | * 描述 18 | * 19 | * @author pj567 20 | * @since 2020/12/27 21 | */ 22 | public class HomeIconDialog extends BaseDialog { 23 | private final TextView tvHomeSearch; 24 | private final TextView tvHomeMenu; 25 | 26 | public HomeIconDialog(@NonNull @NotNull Context context) { 27 | super(context); 28 | setContentView(R.layout.dialog_homeoption); 29 | setCanceledOnTouchOutside(true); 30 | tvHomeSearch = findViewById(R.id.tvHomeSearch); 31 | tvHomeSearch.setText(Hawk.get(HawkConfig.HOME_SEARCH_POSITION, true) ? "上方" : "下方"); 32 | tvHomeMenu = findViewById(R.id.tvHomeMenu); 33 | tvHomeMenu.setText(Hawk.get(HawkConfig.HOME_MENU_POSITION, true) ? "上方" : "下方"); 34 | 35 | findViewById(R.id.llSearch).setOnClickListener(new View.OnClickListener() { 36 | @Override 37 | public void onClick(View v) { 38 | FastClickCheckUtil.check(v); 39 | Hawk.put(HawkConfig.HOME_SEARCH_POSITION, !Hawk.get(HawkConfig.HOME_SEARCH_POSITION, true)); 40 | tvHomeSearch.setText(Hawk.get(HawkConfig.HOME_SEARCH_POSITION, false) ? "上方" : "下方"); 41 | } 42 | }); 43 | findViewById(R.id.llMenu).setOnClickListener(new View.OnClickListener() { 44 | @Override 45 | public void onClick(View v) { 46 | FastClickCheckUtil.check(v); 47 | Hawk.put(HawkConfig.HOME_MENU_POSITION, !Hawk.get(HawkConfig.HOME_MENU_POSITION, true)); 48 | tvHomeMenu.setText(Hawk.get(HawkConfig.HOME_MENU_POSITION, false) ? "上方" : "下方"); 49 | } 50 | }); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /DIY/T/SearchActivity.java: -------------------------------------------------------------------------------- 1 | package com.github.tvbox.osc.ui.activity; 2 | 3 | import android.content.Context; 4 | import android.content.DialogInterface; 5 | import android.content.Intent; 6 | import android.graphics.Rect; 7 | import android.os.Bundle; 8 | import android.text.TextUtils; 9 | import android.view.KeyEvent; 10 | import android.view.View; 11 | import android.view.inputmethod.InputMethodManager; 12 | import android.widget.EditText; 13 | import android.widget.ImageView; 14 | import android.widget.LinearLayout; 15 | import android.widget.TextView; 16 | import android.widget.Toast; 17 | 18 | import androidx.lifecycle.ViewModelProvider; 19 | 20 | import com.chad.library.adapter.base.BaseQuickAdapter; 21 | import com.github.tvbox.osc.R; 22 | import com.github.tvbox.osc.api.ApiConfig; 23 | import com.github.tvbox.osc.base.BaseActivity; 24 | import com.github.tvbox.osc.bean.AbsXml; 25 | import com.github.tvbox.osc.bean.Movie; 26 | import com.github.tvbox.osc.bean.SourceBean; 27 | import com.github.tvbox.osc.event.RefreshEvent; 28 | import com.github.tvbox.osc.event.ServerEvent; 29 | import com.github.tvbox.osc.server.ControlManager; 30 | import com.github.tvbox.osc.ui.adapter.PinyinAdapter; 31 | import com.github.tvbox.osc.ui.adapter.SearchAdapter; 32 | import com.github.tvbox.osc.ui.dialog.RemoteDialog; 33 | import com.github.tvbox.osc.ui.dialog.SearchCheckboxDialog; 34 | import com.github.tvbox.osc.ui.tv.QRCodeGen; 35 | import com.github.tvbox.osc.ui.tv.widget.SearchKeyboard; 36 | import com.github.tvbox.osc.util.FastClickCheckUtil; 37 | import com.github.tvbox.osc.util.HawkConfig; 38 | import com.github.tvbox.osc.util.SearchHelper; 39 | import com.github.tvbox.osc.util.js.JSEngine; 40 | import com.github.tvbox.osc.viewmodel.SourceViewModel; 41 | import com.google.gson.JsonArray; 42 | import com.google.gson.JsonElement; 43 | import com.google.gson.JsonObject; 44 | import com.google.gson.JsonParser; 45 | import com.lzy.okgo.OkGo; 46 | import com.lzy.okgo.callback.AbsCallback; 47 | import com.lzy.okgo.model.Response; 48 | import com.orhanobut.hawk.Hawk; 49 | import com.owen.tvrecyclerview.widget.TvRecyclerView; 50 | import com.owen.tvrecyclerview.widget.V7GridLayoutManager; 51 | import com.owen.tvrecyclerview.widget.V7LinearLayoutManager; 52 | 53 | import org.greenrobot.eventbus.EventBus; 54 | import org.greenrobot.eventbus.Subscribe; 55 | import org.greenrobot.eventbus.ThreadMode; 56 | 57 | import java.util.ArrayList; 58 | import java.util.Arrays; 59 | import java.util.HashMap; 60 | import java.util.List; 61 | import java.util.concurrent.ExecutorService; 62 | import java.util.concurrent.Executors; 63 | import java.util.concurrent.atomic.AtomicInteger; 64 | 65 | /** 66 | * @author pj567 67 | * @date :2020/12/23 68 | * @description: 69 | */ 70 | public class SearchActivity extends BaseActivity { 71 | private LinearLayout llLayout; 72 | private TvRecyclerView mGridView; 73 | private TvRecyclerView mGridViewWord; 74 | SourceViewModel sourceViewModel; 75 | private EditText etSearch; 76 | private TextView tvSearch; 77 | private TextView tvClear; 78 | private SearchKeyboard keyboard; 79 | private TextView tvAddress; 80 | private ImageView ivQRCode; 81 | private SearchAdapter searchAdapter; 82 | private PinyinAdapter wordAdapter; 83 | private String searchTitle = ""; 84 | private ImageView tvSearchCheckbox; 85 | private static HashMap mCheckSources = null; 86 | private SearchCheckboxDialog mSearchCheckboxDialog = null; 87 | 88 | @Override 89 | protected int getLayoutResID() { 90 | return R.layout.activity_search; 91 | } 92 | 93 | @Override 94 | protected void init() { 95 | initView(); 96 | initViewModel(); 97 | initData(); 98 | } 99 | 100 | private List pauseRunnable = null; 101 | 102 | @Override 103 | protected void onResume() { 104 | super.onResume(); 105 | if (pauseRunnable != null && pauseRunnable.size() > 0) { 106 | searchExecutorService = Executors.newFixedThreadPool(5); 107 | allRunCount.set(pauseRunnable.size()); 108 | for (Runnable runnable : pauseRunnable) { 109 | searchExecutorService.execute(runnable); 110 | } 111 | pauseRunnable.clear(); 112 | pauseRunnable = null; 113 | } 114 | } 115 | 116 | private boolean isKeyboardHidden() { 117 | final View rootView = getWindow().getDecorView().findViewById(android.R.id.content); 118 | Rect r = new Rect(); 119 | rootView.getWindowVisibleDisplayFrame(r); 120 | return rootView.getBottom() == r.bottom; 121 | } 122 | 123 | private void initView() { 124 | EventBus.getDefault().register(this); 125 | llLayout = findViewById(R.id.llLayout); 126 | etSearch = findViewById(R.id.etSearch); 127 | tvSearch = findViewById(R.id.tvSearch); 128 | tvSearchCheckbox = findViewById(R.id.tvSearchCheckbox); 129 | tvClear = findViewById(R.id.tvClear); 130 | tvAddress = findViewById(R.id.tvAddress); 131 | ivQRCode = findViewById(R.id.ivQRCode); 132 | mGridView = findViewById(R.id.mGridView); 133 | keyboard = findViewById(R.id.keyBoardRoot); 134 | mGridViewWord = findViewById(R.id.mGridViewWord); 135 | mGridViewWord.setHasFixedSize(true); 136 | mGridViewWord.setLayoutManager(new V7LinearLayoutManager(this.mContext, 1, false)); 137 | wordAdapter = new PinyinAdapter(); 138 | mGridViewWord.setAdapter(wordAdapter); 139 | // Allow Dpad Key switch to other focus 140 | etSearch.setOnKeyListener(new View.OnKeyListener() { 141 | @Override 142 | public boolean onKey(View view, int keyCode, KeyEvent keyEvent) { 143 | if (isKeyboardHidden()) { 144 | if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) { 145 | if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { 146 | ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)) 147 | .showSoftInput(etSearch, 0); 148 | return false; 149 | } 150 | } else if (keyEvent.getAction() == KeyEvent.ACTION_UP) { 151 | int len = etSearch.getText().length(); 152 | if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { 153 | // Avoid show ime keyboard bug 154 | return true; 155 | } else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) { 156 | etSearch.focusSearch(View.FOCUS_DOWN).requestFocus(); 157 | return true; 158 | } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT && (len == 0 || etSearch.getSelectionStart() == len)) { 159 | etSearch.focusSearch(View.FOCUS_RIGHT).requestFocus(); 160 | return true; 161 | } 162 | } 163 | } 164 | return false; 165 | } 166 | }); 167 | wordAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() { 168 | @Override 169 | public void onItemClick(BaseQuickAdapter adapter, View view, int position) { 170 | search(wordAdapter.getItem(position)); 171 | } 172 | }); 173 | mGridView.setHasFixedSize(true); 174 | // lite 175 | if (Hawk.get(HawkConfig.SEARCH_VIEW, 0) == 0) 176 | mGridView.setLayoutManager(new V7LinearLayoutManager(this.mContext, 1, false)); 177 | // with preview 178 | else 179 | mGridView.setLayoutManager(new V7GridLayoutManager(this.mContext, 3)); 180 | searchAdapter = new SearchAdapter(); 181 | mGridView.setAdapter(searchAdapter); 182 | searchAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() { 183 | @Override 184 | public void onItemClick(BaseQuickAdapter adapter, View view, int position) { 185 | FastClickCheckUtil.check(view); 186 | Movie.Video video = searchAdapter.getData().get(position); 187 | if (video != null) { 188 | try { 189 | if (searchExecutorService != null) { 190 | pauseRunnable = searchExecutorService.shutdownNow(); 191 | searchExecutorService = null; 192 | JSEngine.getInstance().stopAll(); 193 | } 194 | } catch (Throwable th) { 195 | th.printStackTrace(); 196 | } 197 | Bundle bundle = new Bundle(); 198 | bundle.putString("id", video.id); 199 | bundle.putString("sourceKey", video.sourceKey); 200 | jumpActivity(DetailActivity.class, bundle); 201 | } 202 | } 203 | }); 204 | tvSearch.setOnClickListener(new View.OnClickListener() { 205 | @Override 206 | public void onClick(View v) { 207 | FastClickCheckUtil.check(v); 208 | String wd = etSearch.getText().toString().trim(); 209 | if (!TextUtils.isEmpty(wd)) { 210 | search(wd); 211 | } else { 212 | Toast.makeText(mContext, getString(R.string.search_input), Toast.LENGTH_SHORT).show(); 213 | } 214 | } 215 | }); 216 | tvClear.setOnClickListener(new View.OnClickListener() { 217 | @Override 218 | public void onClick(View v) { 219 | FastClickCheckUtil.check(v); 220 | etSearch.setText(""); 221 | } 222 | }); 223 | keyboard.setOnSearchKeyListener(new SearchKeyboard.OnSearchKeyListener() { 224 | @Override 225 | public void onSearchKey(int pos, String key) { 226 | if (pos > 1) { 227 | String text = etSearch.getText().toString().trim(); 228 | text += key; 229 | etSearch.setText(text); 230 | if (text.length() > 0) { 231 | loadRec(text); 232 | } 233 | } else if (pos == 1) { 234 | String text = etSearch.getText().toString().trim(); 235 | if (text.length() > 0) { 236 | text = text.substring(0, text.length() - 1); 237 | etSearch.setText(text); 238 | } 239 | if (text.length() > 0) { 240 | loadRec(text); 241 | } 242 | } else if (pos == 0) { 243 | RemoteDialog remoteDialog = new RemoteDialog(mContext); 244 | remoteDialog.show(); 245 | } 246 | } 247 | }); 248 | tvSearchCheckbox.setOnClickListener(new View.OnClickListener() { 249 | @Override 250 | public void onClick(View view) { 251 | if (mSearchCheckboxDialog == null) { 252 | List allSourceBean = ApiConfig.get().getSourceBeanList(); 253 | List searchAbleSource = new ArrayList<>(); 254 | for (SourceBean sourceBean : allSourceBean) { 255 | if (sourceBean.isSearchable()) { 256 | searchAbleSource.add(sourceBean); 257 | } 258 | } 259 | mSearchCheckboxDialog = new SearchCheckboxDialog(SearchActivity.this, searchAbleSource, mCheckSources); 260 | } 261 | mSearchCheckboxDialog.setOnDismissListener(new DialogInterface.OnDismissListener() { 262 | @Override 263 | public void onDismiss(DialogInterface dialog) { 264 | dialog.dismiss(); 265 | } 266 | }); 267 | mSearchCheckboxDialog.show(); 268 | } 269 | }); 270 | setLoadSir(llLayout); 271 | } 272 | 273 | private void initViewModel() { 274 | sourceViewModel = new ViewModelProvider(this).get(SourceViewModel.class); 275 | } 276 | 277 | /** 278 | * 拼音联想 279 | */ 280 | private void loadRec(String key) { 281 | // OkGo.get("https://s.video.qq.com/smartbox") 282 | // .params("plat", 2) 283 | // .params("ver", 0) 284 | // .params("num", 10) 285 | // .params("otype", "json") 286 | // .params("query", key) 287 | // .execute(new AbsCallback() { 288 | // @Override 289 | // public void onSuccess(Response response) { 290 | // try { 291 | // ArrayList hots = new ArrayList<>(); 292 | // String result = response.body(); 293 | // JsonObject json = JsonParser.parseString(result.substring(result.indexOf("{"), result.lastIndexOf("}") + 1)).getAsJsonObject(); 294 | // JsonArray itemList = json.get("item").getAsJsonArray(); 295 | // for (JsonElement ele : itemList) { 296 | // JsonObject obj = (JsonObject) ele; 297 | // hots.add(obj.get("word").getAsString().trim()); 298 | // } 299 | // wordAdapter.setNewData(hots); 300 | // } catch (Throwable th) { 301 | // th.printStackTrace(); 302 | // } 303 | // } 304 | 305 | // @Override 306 | // public String convertResponse(okhttp3.Response response) throws Throwable { 307 | // return response.body().string(); 308 | // } 309 | // }); 310 | OkGo.get("https://suggest.video.iqiyi.com/") 311 | .params("if", "mobile") 312 | .params("key", key) 313 | .execute(new AbsCallback() { 314 | @Override 315 | public void onSuccess(Response response) { 316 | try { 317 | ArrayList hots = new ArrayList<>(); 318 | String result = response.body(); 319 | JsonObject json = JsonParser.parseString(result).getAsJsonObject(); 320 | JsonArray itemList = json.get("data").getAsJsonArray(); 321 | for (JsonElement ele : itemList) { 322 | JsonObject obj = (JsonObject) ele; 323 | hots.add(obj.get("name").getAsString().trim().replaceAll("<|>|《|》|-", "")); 324 | } 325 | wordAdapter.setNewData(hots); 326 | } catch (Throwable th) { 327 | th.printStackTrace(); 328 | } 329 | } 330 | 331 | @Override 332 | public String convertResponse(okhttp3.Response response) throws Throwable { 333 | return response.body().string(); 334 | } 335 | }); 336 | 337 | } 338 | 339 | private void initData() { 340 | refreshQRCode(); 341 | initCheckedSourcesForSearch(); 342 | Intent intent = getIntent(); 343 | if (intent != null && intent.hasExtra("title")) { 344 | String title = intent.getStringExtra("title"); 345 | showLoading(); 346 | search(title); 347 | } 348 | // 加载热词 349 | loadHotSearch(); 350 | } 351 | 352 | //load hot search 353 | private void loadHotSearch() { 354 | OkGo.get("https://node.video.qq.com/x/api/hot_search") 355 | .params("channdlId", "0") 356 | .params("_", System.currentTimeMillis()) 357 | .execute(new AbsCallback() { 358 | @Override 359 | public void onSuccess(Response response) { 360 | try { 361 | ArrayList hots = new ArrayList<>(); 362 | JsonObject mapResult = JsonParser.parseString(response.body()) 363 | .getAsJsonObject() 364 | .get("data").getAsJsonObject() 365 | .get("mapResult").getAsJsonObject(); 366 | List groupIndex = Arrays.asList("0", "1", "2", "3", "5"); 367 | for (String index : groupIndex) { 368 | JsonArray itemList = mapResult.get(index).getAsJsonObject() 369 | .get("listInfo").getAsJsonArray(); 370 | for (JsonElement ele : itemList) { 371 | JsonObject obj = (JsonObject) ele; 372 | String hotKey = obj.get("title").getAsString().trim().replaceAll("<|>|《|》|-", "").split(" ")[0]; 373 | if (!hots.contains(hotKey)) 374 | hots.add(hotKey); 375 | } 376 | } 377 | 378 | wordAdapter.setNewData(hots); 379 | } catch (Throwable th) { 380 | th.printStackTrace(); 381 | } 382 | } 383 | 384 | @Override 385 | public String convertResponse(okhttp3.Response response) throws Throwable { 386 | return response.body().string(); 387 | } 388 | }); 389 | } 390 | 391 | private void refreshQRCode() { 392 | String address = ControlManager.get().getAddress(false); 393 | tvAddress.setText(String.format("远程搜索使用手机/电脑扫描下面二维码或者直接浏览器访问地址\n%s", address)); 394 | ivQRCode.setImageBitmap(QRCodeGen.generateBitmap(address, 300, 300)); 395 | } 396 | 397 | @Subscribe(threadMode = ThreadMode.MAIN) 398 | public void server(ServerEvent event) { 399 | if (event.type == ServerEvent.SERVER_SEARCH) { 400 | String title = (String) event.obj; 401 | showLoading(); 402 | search(title); 403 | } 404 | } 405 | 406 | @Subscribe(threadMode = ThreadMode.MAIN) 407 | public void refresh(RefreshEvent event) { 408 | if (event.type == RefreshEvent.TYPE_SEARCH_RESULT) { 409 | try { 410 | searchData(event.obj == null ? null : (AbsXml) event.obj); 411 | } catch (Exception e) { 412 | searchData(null); 413 | } 414 | } 415 | } 416 | 417 | private void initCheckedSourcesForSearch() { 418 | mCheckSources = SearchHelper.getSourcesForSearch(); 419 | } 420 | 421 | public static void setCheckedSourcesForSearch(HashMap checkedSources) { 422 | mCheckSources = checkedSources; 423 | } 424 | 425 | private void search(String title) { 426 | cancel(); 427 | showLoading(); 428 | this.searchTitle = title; 429 | mGridView.setVisibility(View.INVISIBLE); 430 | searchAdapter.setNewData(new ArrayList<>()); 431 | searchResult(); 432 | } 433 | 434 | private ExecutorService searchExecutorService = null; 435 | private final AtomicInteger allRunCount = new AtomicInteger(0); 436 | 437 | private void searchResult() { 438 | try { 439 | if (searchExecutorService != null) { 440 | searchExecutorService.shutdownNow(); 441 | searchExecutorService = null; 442 | JSEngine.getInstance().stopAll(); 443 | } 444 | } catch (Throwable th) { 445 | th.printStackTrace(); 446 | } finally { 447 | searchAdapter.setNewData(new ArrayList<>()); 448 | allRunCount.set(0); 449 | } 450 | searchExecutorService = Executors.newFixedThreadPool(5); 451 | List searchRequestList = new ArrayList<>(); 452 | searchRequestList.addAll(ApiConfig.get().getSourceBeanList()); 453 | SourceBean home = ApiConfig.get().getHomeSourceBean(); 454 | searchRequestList.remove(home); 455 | searchRequestList.add(0, home); 456 | 457 | ArrayList siteKey = new ArrayList<>(); 458 | for (SourceBean bean : searchRequestList) { 459 | if (!bean.isSearchable()) { 460 | continue; 461 | } 462 | if (mCheckSources != null && !mCheckSources.containsKey(bean.getKey())) { 463 | continue; 464 | } 465 | siteKey.add(bean.getKey()); 466 | allRunCount.incrementAndGet(); 467 | } 468 | if (siteKey.size() <= 0) { 469 | Toast.makeText(mContext, getString(R.string.search_site), Toast.LENGTH_SHORT).show(); 470 | showEmpty(); 471 | return; 472 | } 473 | for (String key : siteKey) { 474 | searchExecutorService.execute(new Runnable() { 475 | @Override 476 | public void run() { 477 | sourceViewModel.getSearch(key, searchTitle); 478 | } 479 | }); 480 | } 481 | } 482 | 483 | private boolean matchSearchResult(String name, String searchTitle) { 484 | if (TextUtils.isEmpty(name) || TextUtils.isEmpty(searchTitle)) return false; 485 | searchTitle = searchTitle.trim(); 486 | String[] arr = searchTitle.split("\\s+"); 487 | int matchNum = 0; 488 | for (String one : arr) { 489 | if (name.contains(one)) matchNum++; 490 | } 491 | return matchNum == arr.length; 492 | } 493 | 494 | private void searchData(AbsXml absXml) { 495 | if (absXml != null && absXml.movie != null && absXml.movie.videoList != null && absXml.movie.videoList.size() > 0) { 496 | List data = new ArrayList<>(); 497 | for (Movie.Video video : absXml.movie.videoList) { 498 | data.add(video); 499 | } 500 | if (searchAdapter.getData().size() > 0) { 501 | searchAdapter.addData(data); 502 | } else { 503 | showSuccess(); 504 | mGridView.setVisibility(View.VISIBLE); 505 | searchAdapter.setNewData(data); 506 | } 507 | } 508 | 509 | int count = allRunCount.decrementAndGet(); 510 | if (count <= 0) { 511 | if (searchAdapter.getData().size() <= 0) { 512 | showEmpty(); 513 | } 514 | cancel(); 515 | } 516 | } 517 | 518 | private void cancel() { 519 | OkGo.getInstance().cancelTag("search"); 520 | } 521 | 522 | @Override 523 | protected void onDestroy() { 524 | super.onDestroy(); 525 | cancel(); 526 | try { 527 | if (searchExecutorService != null) { 528 | searchExecutorService.shutdownNow(); 529 | searchExecutorService = null; 530 | JSEngine.getInstance().stopAll(); 531 | } 532 | } catch (Throwable th) { 533 | th.printStackTrace(); 534 | } 535 | EventBus.getDefault().unregister(this); 536 | } 537 | } 538 | -------------------------------------------------------------------------------- /DIY/T/UserFragment.java: -------------------------------------------------------------------------------- 1 | package com.github.tvbox.osc.ui.fragment; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | import android.view.animation.BounceInterpolator; 7 | import android.widget.LinearLayout; 8 | import android.widget.Toast; 9 | 10 | import com.chad.library.adapter.base.BaseQuickAdapter; 11 | import com.github.tvbox.osc.R; 12 | import com.github.tvbox.osc.api.ApiConfig; 13 | import com.github.tvbox.osc.base.BaseLazyFragment; 14 | import com.github.tvbox.osc.bean.Movie; 15 | import com.github.tvbox.osc.bean.VodInfo; 16 | import com.github.tvbox.osc.cache.RoomDataManger; 17 | import com.github.tvbox.osc.event.ServerEvent; 18 | import com.github.tvbox.osc.ui.activity.CollectActivity; 19 | import com.github.tvbox.osc.ui.activity.DetailActivity; 20 | import com.github.tvbox.osc.ui.activity.DriveActivity; 21 | import com.github.tvbox.osc.ui.activity.FastSearchActivity; 22 | import com.github.tvbox.osc.ui.activity.HistoryActivity; 23 | import com.github.tvbox.osc.ui.activity.LivePlayActivity; 24 | import com.github.tvbox.osc.ui.activity.PushActivity; 25 | import com.github.tvbox.osc.ui.activity.SearchActivity; 26 | import com.github.tvbox.osc.ui.activity.SettingActivity; 27 | import com.github.tvbox.osc.ui.adapter.HomeHotVodAdapter; 28 | import com.github.tvbox.osc.util.FastClickCheckUtil; 29 | import com.github.tvbox.osc.util.HawkConfig; 30 | import com.google.gson.Gson; 31 | import com.google.gson.JsonArray; 32 | import com.google.gson.JsonElement; 33 | import com.google.gson.JsonObject; 34 | import com.lzy.okgo.OkGo; 35 | import com.lzy.okgo.callback.AbsCallback; 36 | import com.lzy.okgo.model.Response; 37 | import com.orhanobut.hawk.Hawk; 38 | import com.owen.tvrecyclerview.widget.TvRecyclerView; 39 | import com.owen.tvrecyclerview.widget.V7GridLayoutManager; 40 | 41 | import org.greenrobot.eventbus.EventBus; 42 | import org.greenrobot.eventbus.Subscribe; 43 | import org.greenrobot.eventbus.ThreadMode; 44 | 45 | import java.util.ArrayList; 46 | import java.util.Calendar; 47 | import java.util.List; 48 | 49 | /** 50 | * @author pj567 51 | * @date :2021/3/9 52 | * @description: 53 | */ 54 | public class UserFragment extends BaseLazyFragment implements View.OnClickListener { 55 | private LinearLayout tvDrive; 56 | private LinearLayout tvLive; 57 | private LinearLayout tvSearch; 58 | private LinearLayout tvSetting; 59 | private LinearLayout tvHistory; 60 | private LinearLayout tvCollect; 61 | private LinearLayout tvPush; 62 | public static HomeHotVodAdapter homeHotVodAdapter; 63 | private List homeSourceRec; 64 | public static TvRecyclerView tvHotListForGrid; 65 | public static TvRecyclerView tvHotListForLine; 66 | 67 | public static UserFragment newInstance() { 68 | return new UserFragment(); 69 | } 70 | 71 | public static UserFragment newInstance(List recVod) { 72 | return new UserFragment().setArguments(recVod); 73 | } 74 | 75 | public UserFragment setArguments(List recVod) { 76 | this.homeSourceRec = recVod; 77 | return this; 78 | } 79 | 80 | @Override 81 | public void onFragmentResume() { 82 | 83 | // takagen99: Initialize Icon Placement 84 | if (!Hawk.get(HawkConfig.HOME_SEARCH_POSITION, true)) { 85 | tvSearch.setVisibility(View.VISIBLE); 86 | } else { 87 | tvSearch.setVisibility(View.GONE); 88 | } 89 | if (!Hawk.get(HawkConfig.HOME_MENU_POSITION, true)) { 90 | tvSetting.setVisibility(View.VISIBLE); 91 | } else { 92 | tvSetting.setVisibility(View.GONE); 93 | } 94 | 95 | super.onFragmentResume(); 96 | if (Hawk.get(HawkConfig.HOME_REC, 0) == 2) { 97 | List allVodRecord = RoomDataManger.getAllVodRecord(20); 98 | List vodList = new ArrayList<>(); 99 | for (VodInfo vodInfo : allVodRecord) { 100 | Movie.Video vod = new Movie.Video(); 101 | vod.id = vodInfo.id; 102 | vod.sourceKey = vodInfo.sourceKey; 103 | vod.name = vodInfo.name; 104 | vod.pic = vodInfo.pic; 105 | if (vodInfo.playNote != null && !vodInfo.playNote.isEmpty()) 106 | vod.note = "上次看到" + vodInfo.playNote; 107 | vodList.add(vod); 108 | } 109 | homeHotVodAdapter.setNewData(vodList); 110 | } 111 | } 112 | 113 | @Override 114 | protected int getLayoutResID() { 115 | return R.layout.fragment_user; 116 | } 117 | 118 | @Override 119 | protected void init() { 120 | EventBus.getDefault().register(this); 121 | tvDrive = findViewById(R.id.tvDrive); 122 | tvLive = findViewById(R.id.tvLive); 123 | tvSearch = findViewById(R.id.tvSearch); 124 | tvSetting = findViewById(R.id.tvSetting); 125 | tvCollect = findViewById(R.id.tvFavorite); 126 | tvHistory = findViewById(R.id.tvHistory); 127 | tvPush = findViewById(R.id.tvPush); 128 | tvDrive.setOnClickListener(this); 129 | tvLive.setOnClickListener(this); 130 | tvSearch.setOnClickListener(this); 131 | tvSetting.setOnClickListener(this); 132 | tvHistory.setOnClickListener(this); 133 | tvPush.setOnClickListener(this); 134 | tvCollect.setOnClickListener(this); 135 | tvDrive.setOnFocusChangeListener(focusChangeListener); 136 | tvLive.setOnFocusChangeListener(focusChangeListener); 137 | tvSearch.setOnFocusChangeListener(focusChangeListener); 138 | tvSetting.setOnFocusChangeListener(focusChangeListener); 139 | tvHistory.setOnFocusChangeListener(focusChangeListener); 140 | tvPush.setOnFocusChangeListener(focusChangeListener); 141 | tvCollect.setOnFocusChangeListener(focusChangeListener); 142 | tvHotListForLine = findViewById(R.id.tvHotListForLine); 143 | tvHotListForGrid = findViewById(R.id.tvHotListForGrid); 144 | tvHotListForGrid.setHasFixedSize(true); 145 | tvHotListForGrid.setLayoutManager(new V7GridLayoutManager(this.mContext, 5)); 146 | homeHotVodAdapter = new HomeHotVodAdapter(); 147 | homeHotVodAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() { 148 | @Override 149 | public void onItemClick(BaseQuickAdapter adapter, View view, int position) { 150 | if (ApiConfig.get().getSourceBeanList().isEmpty()) 151 | return; 152 | Movie.Video vod = ((Movie.Video) adapter.getItem(position)); 153 | 154 | // takagen99: CHeck if in Delete Mode 155 | if ((vod.id != null && !vod.id.isEmpty()) && (Hawk.get(HawkConfig.HOME_REC, 0) == 2) && HawkConfig.hotVodDelete) { 156 | homeHotVodAdapter.remove(position); 157 | VodInfo vodInfo = RoomDataManger.getVodInfo(vod.sourceKey, vod.id); 158 | RoomDataManger.deleteVodRecord(vod.sourceKey, vodInfo); 159 | Toast.makeText(mContext, getString(R.string.hm_hist_del), Toast.LENGTH_SHORT).show(); 160 | } else if (vod.id != null && !vod.id.isEmpty()) { 161 | Bundle bundle = new Bundle(); 162 | bundle.putString("id", vod.id); 163 | bundle.putString("sourceKey", vod.sourceKey); 164 | if (vod.id.startsWith("msearch:")) { 165 | bundle.putString("title", vod.name); 166 | jumpActivity(FastSearchActivity.class, bundle); 167 | } else { 168 | jumpActivity(DetailActivity.class, bundle); 169 | } 170 | } else { 171 | Intent newIntent = new Intent(mContext, SearchActivity.class); 172 | newIntent.putExtra("title", vod.name); 173 | newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 174 | mActivity.startActivity(newIntent); 175 | } 176 | } 177 | }); 178 | // takagen99 : Long press to trigger Delete Mode for VOD History on Home Page 179 | homeHotVodAdapter.setOnItemLongClickListener(new BaseQuickAdapter.OnItemLongClickListener() { 180 | @Override 181 | public boolean onItemLongClick(BaseQuickAdapter adapter, View view, int position) { 182 | if (ApiConfig.get().getSourceBeanList().isEmpty()) 183 | return false; 184 | Movie.Video vod = ((Movie.Video) adapter.getItem(position)); 185 | // Additional Check if : Home Rec 0=豆瓣, 1=推荐, 2=历史 186 | if ((vod.id != null && !vod.id.isEmpty()) && (Hawk.get(HawkConfig.HOME_REC, 0) == 2)) { 187 | HawkConfig.hotVodDelete = !HawkConfig.hotVodDelete; 188 | homeHotVodAdapter.notifyDataSetChanged(); 189 | } else { 190 | Intent newIntent = new Intent(mContext, FastSearchActivity.class); 191 | newIntent.putExtra("title", vod.name); 192 | newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 193 | mActivity.startActivity(newIntent); 194 | } 195 | return true; 196 | } 197 | }); 198 | // Grid View 199 | tvHotListForGrid.setOnItemListener(new TvRecyclerView.OnItemListener() { 200 | @Override 201 | public void onItemPreSelected(TvRecyclerView parent, View itemView, int position) { 202 | itemView.animate().scaleX(1.0f).scaleY(1.0f).setDuration(300).setInterpolator(new BounceInterpolator()).start(); 203 | } 204 | 205 | @Override 206 | public void onItemSelected(TvRecyclerView parent, View itemView, int position) { 207 | itemView.animate().scaleX(1.05f).scaleY(1.05f).setDuration(300).setInterpolator(new BounceInterpolator()).start(); 208 | } 209 | 210 | @Override 211 | public void onItemClick(TvRecyclerView parent, View itemView, int position) { 212 | 213 | } 214 | }); 215 | tvHotListForGrid.setAdapter(homeHotVodAdapter); 216 | // Line View 217 | tvHotListForLine.setOnItemListener(new TvRecyclerView.OnItemListener() { 218 | @Override 219 | public void onItemPreSelected(TvRecyclerView parent, View itemView, int position) { 220 | itemView.animate().scaleX(1.0f).scaleY(1.0f).setDuration(300).setInterpolator(new BounceInterpolator()).start(); 221 | } 222 | 223 | @Override 224 | public void onItemSelected(TvRecyclerView parent, View itemView, int position) { 225 | itemView.animate().scaleX(1.05f).scaleY(1.05f).setDuration(300).setInterpolator(new BounceInterpolator()).start(); 226 | } 227 | 228 | @Override 229 | public void onItemClick(TvRecyclerView parent, View itemView, int position) { 230 | 231 | } 232 | }); 233 | tvHotListForLine.setAdapter(homeHotVodAdapter); 234 | 235 | initHomeHotVod(homeHotVodAdapter); 236 | 237 | // Swifly: Home Style 238 | if (Hawk.get(HawkConfig.HOME_REC_STYLE, false)) { 239 | tvHotListForGrid.setVisibility(View.VISIBLE); 240 | tvHotListForLine.setVisibility(View.GONE); 241 | } else { 242 | tvHotListForGrid.setVisibility(View.GONE); 243 | tvHotListForLine.setVisibility(View.VISIBLE); 244 | } 245 | } 246 | 247 | private void initHomeHotVod(HomeHotVodAdapter adapter) { 248 | if (Hawk.get(HawkConfig.HOME_REC, 0) == 1) { 249 | if (homeSourceRec != null) { 250 | adapter.setNewData(homeSourceRec); 251 | } 252 | return; 253 | } else if (Hawk.get(HawkConfig.HOME_REC, 0) == 2) { 254 | return; 255 | } 256 | try { 257 | Calendar cal = Calendar.getInstance(); 258 | int year = cal.get(Calendar.YEAR); 259 | int month = cal.get(Calendar.MONTH) + 1; 260 | int day = cal.get(Calendar.DATE); 261 | String today = String.format("%d%d%d", year, month, day); 262 | String requestDay = Hawk.get("home_hot_day", ""); 263 | if (requestDay.equals(today)) { 264 | String json = Hawk.get("home_hot", ""); 265 | if (!json.isEmpty()) { 266 | adapter.setNewData(loadHots(json)); 267 | return; 268 | } 269 | } 270 | OkGo.get("https://movie.douban.com/j/new_search_subjects?sort=U&range=0,10&tags=&playable=1&start=0&year_range=" + year + "," + year).execute(new AbsCallback() { 271 | @Override 272 | public void onSuccess(Response response) { 273 | String netJson = response.body(); 274 | Hawk.put("home_hot_day", today); 275 | Hawk.put("home_hot", netJson); 276 | mActivity.runOnUiThread(new Runnable() { 277 | @Override 278 | public void run() { 279 | adapter.setNewData(loadHots(netJson)); 280 | } 281 | }); 282 | } 283 | 284 | @Override 285 | public String convertResponse(okhttp3.Response response) throws Throwable { 286 | return response.body().string(); 287 | } 288 | }); 289 | } catch (Throwable th) { 290 | th.printStackTrace(); 291 | } 292 | } 293 | 294 | private ArrayList loadHots(String json) { 295 | ArrayList result = new ArrayList<>(); 296 | try { 297 | JsonObject infoJson = new Gson().fromJson(json, JsonObject.class); 298 | JsonArray array = infoJson.getAsJsonArray("data"); 299 | for (JsonElement ele : array) { 300 | JsonObject obj = (JsonObject) ele; 301 | Movie.Video vod = new Movie.Video(); 302 | vod.name = obj.get("title").getAsString(); 303 | vod.note = obj.get("rate").getAsString(); 304 | vod.pic = obj.get("cover").getAsString(); 305 | result.add(vod); 306 | } 307 | } catch (Throwable th) { 308 | 309 | } 310 | return result; 311 | } 312 | 313 | private final View.OnFocusChangeListener focusChangeListener = new View.OnFocusChangeListener() { 314 | @Override 315 | public void onFocusChange(View v, boolean hasFocus) { 316 | if (hasFocus) 317 | v.animate().scaleX(1.05f).scaleY(1.05f).setDuration(300).setInterpolator(new BounceInterpolator()).start(); 318 | else 319 | v.animate().scaleX(1.0f).scaleY(1.0f).setDuration(300).setInterpolator(new BounceInterpolator()).start(); 320 | } 321 | }; 322 | 323 | @Override 324 | public void onClick(View v) { 325 | 326 | // takagen99: Remove Delete Mode 327 | HawkConfig.hotVodDelete = false; 328 | 329 | FastClickCheckUtil.check(v); 330 | if (v.getId() == R.id.tvLive) { 331 | jumpActivity(LivePlayActivity.class); 332 | } else if (v.getId() == R.id.tvSearch) { 333 | jumpActivity(SearchActivity.class); 334 | } else if (v.getId() == R.id.tvSetting) { 335 | jumpActivity(SettingActivity.class); 336 | } else if (v.getId() == R.id.tvHistory) { 337 | jumpActivity(HistoryActivity.class); 338 | } else if (v.getId() == R.id.tvPush) { 339 | jumpActivity(PushActivity.class); 340 | } else if (v.getId() == R.id.tvFavorite) { 341 | jumpActivity(CollectActivity.class); 342 | } else if (v.getId() == R.id.tvDrive) { 343 | jumpActivity(DriveActivity.class); 344 | } 345 | } 346 | 347 | @Subscribe(threadMode = ThreadMode.MAIN) 348 | public void server(ServerEvent event) { 349 | if (event.type == ServerEvent.SERVER_CONNECTION) { 350 | } 351 | } 352 | 353 | @Override 354 | public void onDestroy() { 355 | super.onDestroy(); 356 | EventBus.getDefault().unregister(this); 357 | } 358 | } -------------------------------------------------------------------------------- /DIY/T/activity_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 21 | 22 | 31 | 32 | 49 | 50 | 63 | 64 | 79 | 80 | 94 | 95 | 109 | 110 | 124 | 125 | 140 | 141 | 156 | 157 | 158 | 159 | 170 | 171 | 180 | 181 | 185 | 186 | 187 | -------------------------------------------------------------------------------- /DIY/T/fragment_user.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 19 | 20 | 21 | 30 | 31 | 43 | 44 | 51 | 52 | 65 | 66 | 67 | 68 | 79 | 80 | 87 | 88 | 101 | 102 | 103 | 104 | 115 | 116 | 123 | 124 | 137 | 138 | 139 | 140 | 151 | 152 | 159 | 160 | 173 | 174 | 175 | 176 | 187 | 188 | 195 | 196 | 209 | 210 | 211 | 212 | 223 | 224 | 231 | 232 | 245 | 246 | 247 | 248 | 259 | 260 | 267 | 268 | 281 | 282 | 283 | 284 | 285 | 286 | 304 | 305 | 321 | 322 | 323 | 324 | -------------------------------------------------------------------------------- /DIY/TVBoxOSC.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhoujck/DIY_TvBox/3720a887c9598f8e5bbf266a78c5693a9ca4feb9/DIY/TVBoxOSC.jks -------------------------------------------------------------------------------- /DIY/app_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhoujck/DIY_TvBox/3720a887c9598f8e5bbf266a78c5693a9ca4feb9/DIY/app_bg.png -------------------------------------------------------------------------------- /DIY/app_bg_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhoujck/DIY_TvBox/3720a887c9598f8e5bbf266a78c5693a9ca4feb9/DIY/app_bg_black.png -------------------------------------------------------------------------------- /DIY/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhoujck/DIY_TvBox/3720a887c9598f8e5bbf266a78c5693a9ca4feb9/DIY/app_icon.png -------------------------------------------------------------------------------- /DIY/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhoujck/DIY_TvBox/3720a887c9598f8e5bbf266a78c5693a9ca4feb9/DIY/bg.jpg -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TVBoxDIY 2 | Fork:https://github.com/CatVodTVOfficial/TVBoxOSC.git 3 | 4 | 源码:https://github.com/lm317379829/TVBoxOSC.git 5 | 6 | # 说明 7 | APK-J Build为本地爬虫-俊版,APK-T Build为本地爬虫taka版 8 | diy-J.sh、diy-T.sh分别为俊版、taka版自定义脚本,可自行修改apk名、背景、图标以及其他源码内容。 9 | 10 | 11 | -------------------------------------------------------------------------------- /diy-J-Jar.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #获取目录 4 | CURRENT_DIR=$(cd $(dirname $0); pwd) 5 | num=$(find $CURRENT_DIR -name gradlew | awk -F"/" '{print NF-1}') 6 | DIR=$(find $CURRENT_DIR -name gradlew | cut -d \/ -f$num) 7 | cd $CURRENT_DIR/$DIR 8 | 9 | #签名 10 | signingConfigs='ICAgIHNpZ25pbmdDb25maWdzIHtcCiAgICAgICAgaWYgKHByb2plY3QuaGFzUHJvcGVydHkoIlJFTEVBU0VfU1RPUkVfRklMRSIpKSB7XAogICAgICAgICAgICBteUNvbmZpZyB7XAogICAgICAgICAgICAgICAgc3RvcmVGaWxlIGZpbGUoUkVMRUFTRV9TVE9SRV9GSUxFKVwKICAgICAgICAgICAgICAgIHN0b3JlUGFzc3dvcmQgUkVMRUFTRV9TVE9SRV9QQVNTV09SRFwKICAgICAgICAgICAgICAgIGtleUFsaWFzIFJFTEVBU0VfS0VZX0FMSUFTXAogICAgICAgICAgICAgICAga2V5UGFzc3dvcmQgUkVMRUFTRV9LRVlfUEFTU1dPUkRcCiAgICAgICAgICAgICAgICB2MVNpZ25pbmdFbmFibGVkIHRydWVcCiAgICAgICAgICAgICAgICB2MlNpZ25pbmdFbmFibGVkIHRydWVcCiAgICAgICAgICAgICAgICBlbmFibGVWM1NpZ25pbmcgPSB0cnVlXAogICAgICAgICAgICAgICAgZW5hYmxlVjRTaWduaW5nID0gdHJ1ZVwKICAgICAgICAgICAgfVwKICAgICAgICB9XAogICAgfVwKXA==' 11 | signingConfig='ICAgICAgICAgICAgaWYgKHByb2plY3QuaGFzUHJvcGVydHkoIlJFTEVBU0VfU1RPUkVfRklMRSIpKSB7XAogICAgICAgICAgICAgICAgc2lnbmluZ0NvbmZpZyBzaWduaW5nQ29uZmlncy5teUNvbmZpZ1wKICAgICAgICAgICAgfVwK' 12 | signingConfigs="$(echo "$signingConfigs" |base64 -d )" 13 | signingConfig="$(echo "$signingConfig" |base64 -d )" 14 | sed -i -e "/defaultConfig {/i\\$signingConfigs " -e "/debug {/a\\$signingConfig " -e "/release {/a\\$signingConfig " $CURRENT_DIR/$DIR/app/build.gradle 15 | cp -f $CURRENT_DIR/DIY/TVBoxOSC.jks $CURRENT_DIR/$DIR/app/TVBoxOSC.jks 16 | cp -f $CURRENT_DIR/DIY/TVBoxOSC.jks $CURRENT_DIR/$DIR/TVBoxOSC.jks 17 | echo "" >>$CURRENT_DIR/$DIR/gradle.properties 18 | echo "RELEASE_STORE_FILE=./TVBoxOSC.jks" >>$CURRENT_DIR/$DIR/gradle.properties 19 | echo "RELEASE_KEY_ALIAS=TVBoxOSC" >>$CURRENT_DIR/$DIR/gradle.properties 20 | echo "RELEASE_STORE_PASSWORD=TVBoxOSC" >>$CURRENT_DIR/$DIR/gradle.properties 21 | echo "RELEASE_KEY_PASSWORD=TVBoxOSC" >>$CURRENT_DIR/$DIR/gradle.properties 22 | 23 | 24 | # 名称修改 25 | sed -i 's/TVBox/糖果影视/g' $CURRENT_DIR/$DIR/app/src/main/res/values/strings.xml 26 | 27 | # 图标修改 28 | cp $CURRENT_DIR/DIY/app_icon.png $CURRENT_DIR/$DIR/app/src/main/res/drawable/app_banner.png 29 | cp $CURRENT_DIR/DIY/app_icon.png $CURRENT_DIR/$DIR/app/src/main/res/drawable-hdpi/app_icon.png 30 | cp $CURRENT_DIR/DIY/app_icon.png $CURRENT_DIR/$DIR/app/src/main/res/drawable-xhdpi/app_icon.png 31 | cp $CURRENT_DIR/DIY/app_icon.png $CURRENT_DIR/$DIR/app/src/main/res/drawable-xxhdpi/app_icon.png 32 | mv $CURRENT_DIR/DIY/app_icon.png $CURRENT_DIR/$DIR/app/src/main/res/drawable-xxxhdpi/app_icon.png 33 | 34 | # 主页UI微调 35 | #cp $CURRENT_DIR/DIY/J/fragment_user.xml $CURRENT_DIR/$DIR/app/src/main/res/layout/fragment_user.xml 36 | 37 | #主页增加每日一言1.0 38 | #cp $CURRENT_DIR/DIY/J/ApiConfig.java $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/api/ApiConfig.java 39 | #cp $CURRENT_DIR/DIY/J/activity_home.xml $CURRENT_DIR/$DIR/app/src/main/res/layout/activity_home.xml 40 | #cp $CURRENT_DIR/DIY/J/HomeActivity.java $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/ui/activity/HomeActivity.java 41 | 42 | # 背景修改 43 | cp $CURRENT_DIR/DIY/app_bg_black.png $CURRENT_DIR/$DIR/app/src/main/res/drawable/app_bg.png 44 | 45 | # 默认设置修改 46 | #cp $CURRENT_DIR/DIY/J/App.java $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/base/App.java 47 | 48 | # 内置接口 49 | sed -i 's#API_URL, ""#API_URL, "https://agit.ai/zhoujck/config/raw/branch/master/box"#g' $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/api/ApiConfig.java 50 | 51 | #自定义epg 52 | #cp $CURRENT_DIR/DIY/epg_data.json $CURRENT_DIR/$DIR/app/src/main/assets/epg_data.json 53 | 54 | #播放界面修改 1.底部控件重排 2.直播增加分辨率显示 55 | #cp $CURRENT_DIR/DIY/J/activity_live_play.xml $CURRENT_DIR/$DIR/app/src/main/res/layout/activity_live_play.xml 56 | #cp $CURRENT_DIR/DIY/J/player_vod_control_view.xml $CURRENT_DIR/$DIR/app/src/main/res/layout/player_vod_control_view.xml 57 | #cp $CURRENT_DIR/DIY/J/VodController.java $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/player/controller/VodController.java 58 | #cp $CURRENT_DIR/DIY/J/LivePlayActivity.java $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/ui/activity/LivePlayActivity.java 59 | 60 | #换源 61 | #cp $CURRENT_DIR/DIY/J/DetailActivity.java $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/ui/activity/DetailActivity.java 62 | 63 | #修改播放器进度条消失时间 64 | #sed -i 's/10000/6000/g' $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/player/controller/VodController.java 65 | 66 | #主界面首页文字修改 67 | #sed -i 's/color_BBFFFFFF/color_FFFFFF/g' $CURRENT_DIR/$DIR/app/src/main/res/layout/item_home_sort.xml 68 | #sed -i 's/color_BBFFFFFF/color_FFFFFF/g' $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/ui/activity/HomeActivity.java 69 | 70 | #进度条颜色 71 | #sed -i 's/color_353744/color_1890FF/g' $CURRENT_DIR/$DIR/app/src/main/res/drawable/shape_player_control_vod_seek.xml 72 | 73 | #共存 74 | #sed -i 's/com.github.tvbox.osc/com.tvbox.q/g' $CURRENT_DIR/$DIR/app/build.gradle 75 | 76 | #FongMi的jar支持 77 | #echo "" >>$CURRENT_DIR/$DIR/app/proguard-rules.pro 78 | #echo "-keep class com.google.gson.**{*;}" >>$CURRENT_DIR/$DIR/app/proguard-rules.pro 79 | 80 | 81 | echo 'DIY end' 82 | -------------------------------------------------------------------------------- /diy-J.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #获取目录 4 | CURRENT_DIR=$(cd $(dirname $0); pwd) 5 | num=$(find $CURRENT_DIR -name gradlew | awk -F"/" '{print NF-1}') 6 | DIR=$(find $CURRENT_DIR -name gradlew | cut -d \/ -f$num) 7 | cd $CURRENT_DIR/$DIR 8 | 9 | #签名 10 | signingConfigs='ICAgIHNpZ25pbmdDb25maWdzIHtcCiAgICAgICAgaWYgKHByb2plY3QuaGFzUHJvcGVydHkoIlJFTEVBU0VfU1RPUkVfRklMRSIpKSB7XAogICAgICAgICAgICBteUNvbmZpZyB7XAogICAgICAgICAgICAgICAgc3RvcmVGaWxlIGZpbGUoUkVMRUFTRV9TVE9SRV9GSUxFKVwKICAgICAgICAgICAgICAgIHN0b3JlUGFzc3dvcmQgUkVMRUFTRV9TVE9SRV9QQVNTV09SRFwKICAgICAgICAgICAgICAgIGtleUFsaWFzIFJFTEVBU0VfS0VZX0FMSUFTXAogICAgICAgICAgICAgICAga2V5UGFzc3dvcmQgUkVMRUFTRV9LRVlfUEFTU1dPUkRcCiAgICAgICAgICAgICAgICB2MVNpZ25pbmdFbmFibGVkIHRydWVcCiAgICAgICAgICAgICAgICB2MlNpZ25pbmdFbmFibGVkIHRydWVcCiAgICAgICAgICAgICAgICBlbmFibGVWM1NpZ25pbmcgPSB0cnVlXAogICAgICAgICAgICAgICAgZW5hYmxlVjRTaWduaW5nID0gdHJ1ZVwKICAgICAgICAgICAgfVwKICAgICAgICB9XAogICAgfVwKXA==' 11 | signingConfig='ICAgICAgICAgICAgaWYgKHByb2plY3QuaGFzUHJvcGVydHkoIlJFTEVBU0VfU1RPUkVfRklMRSIpKSB7XAogICAgICAgICAgICAgICAgc2lnbmluZ0NvbmZpZyBzaWduaW5nQ29uZmlncy5teUNvbmZpZ1wKICAgICAgICAgICAgfVwK' 12 | signingConfigs="$(echo "$signingConfigs" |base64 -d )" 13 | signingConfig="$(echo "$signingConfig" |base64 -d )" 14 | sed -i -e "/defaultConfig {/i\\$signingConfigs " -e "/debug {/a\\$signingConfig " -e "/release {/a\\$signingConfig " $CURRENT_DIR/$DIR/app/build.gradle 15 | cp -f $CURRENT_DIR/DIY/TVBoxOSC.jks $CURRENT_DIR/$DIR/app/TVBoxOSC.jks 16 | cp -f $CURRENT_DIR/DIY/TVBoxOSC.jks $CURRENT_DIR/$DIR/TVBoxOSC.jks 17 | echo "" >>$CURRENT_DIR/$DIR/gradle.properties 18 | echo "RELEASE_STORE_FILE=./TVBoxOSC.jks" >>$CURRENT_DIR/$DIR/gradle.properties 19 | echo "RELEASE_KEY_ALIAS=TVBoxOSC" >>$CURRENT_DIR/$DIR/gradle.properties 20 | echo "RELEASE_STORE_PASSWORD=TVBoxOSC" >>$CURRENT_DIR/$DIR/gradle.properties 21 | echo "RELEASE_KEY_PASSWORD=TVBoxOSC" >>$CURRENT_DIR/$DIR/gradle.properties 22 | 23 | 24 | # 名称修改 25 | sed -i 's/TVBox/糖果影视/g' $CURRENT_DIR/$DIR/app/src/main/res/values/strings.xml 26 | 27 | # 图标修改 28 | cp $CURRENT_DIR/DIY/app_icon.png $CURRENT_DIR/$DIR/app/src/main/res/drawable/app_banner.png 29 | cp $CURRENT_DIR/DIY/app_icon.png $CURRENT_DIR/$DIR/app/src/main/res/drawable-hdpi/app_icon.png 30 | cp $CURRENT_DIR/DIY/app_icon.png $CURRENT_DIR/$DIR/app/src/main/res/drawable-xhdpi/app_icon.png 31 | cp $CURRENT_DIR/DIY/app_icon.png $CURRENT_DIR/$DIR/app/src/main/res/drawable-xxhdpi/app_icon.png 32 | mv $CURRENT_DIR/DIY/app_icon.png $CURRENT_DIR/$DIR/app/src/main/res/drawable-xxxhdpi/app_icon.png 33 | 34 | # 主页UI微调 35 | cp $CURRENT_DIR/DIY/J/fragment_user.xml $CURRENT_DIR/$DIR/app/src/main/res/layout/fragment_user.xml 36 | 37 | #主页增加每日一言1.0 38 | cp $CURRENT_DIR/DIY/J/ApiConfig.java $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/api/ApiConfig.java 39 | cp $CURRENT_DIR/DIY/J/activity_home.xml $CURRENT_DIR/$DIR/app/src/main/res/layout/activity_home.xml 40 | cp $CURRENT_DIR/DIY/J/HomeActivity.java $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/ui/activity/HomeActivity.java 41 | 42 | # 背景修改 43 | cp $CURRENT_DIR/DIY/app_bg_black.png $CURRENT_DIR/$DIR/app/src/main/res/drawable/app_bg.png 44 | 45 | # 默认设置修改 46 | cp $CURRENT_DIR/DIY/J/App.java $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/base/App.java 47 | 48 | # 内置接口 49 | sed -i 's#API_URL, ""#API_URL, "https://agit.ai/zhoujck/config/raw/branch/master/box"#g' $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/api/ApiConfig.java 50 | 51 | #自定义epg 52 | #cp $CURRENT_DIR/DIY/epg_data.json $CURRENT_DIR/$DIR/app/src/main/assets/epg_data.json 53 | 54 | #播放界面修改 1.底部控件重排 2.直播增加分辨率显示 55 | cp $CURRENT_DIR/DIY/J/activity_live_play.xml $CURRENT_DIR/$DIR/app/src/main/res/layout/activity_live_play.xml 56 | cp $CURRENT_DIR/DIY/J/player_vod_control_view.xml $CURRENT_DIR/$DIR/app/src/main/res/layout/player_vod_control_view.xml 57 | cp $CURRENT_DIR/DIY/J/VodController.java $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/player/controller/VodController.java 58 | cp $CURRENT_DIR/DIY/J/LivePlayActivity.java $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/ui/activity/LivePlayActivity.java 59 | 60 | #换源 61 | #cp $CURRENT_DIR/DIY/J/DetailActivity.java $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/ui/activity/DetailActivity.java 62 | 63 | #修改播放器进度条消失时间 64 | sed -i 's/10000/6000/g' $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/player/controller/VodController.java 65 | 66 | #主界面首页文字修改 67 | sed -i 's/color_BBFFFFFF/color_FFFFFF/g' $CURRENT_DIR/$DIR/app/src/main/res/layout/item_home_sort.xml 68 | sed -i 's/color_BBFFFFFF/color_FFFFFF/g' $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/ui/activity/HomeActivity.java 69 | 70 | #进度条颜色 71 | sed -i 's/color_353744/color_1890FF/g' $CURRENT_DIR/$DIR/app/src/main/res/drawable/shape_player_control_vod_seek.xml 72 | 73 | #共存 74 | sed -i 's/com.github.tvbox.osc/com.tvbox.q/g' $CURRENT_DIR/$DIR/app/build.gradle 75 | 76 | #添加PY支持 77 | wget --no-check-certificate -qO- "https://raw.githubusercontent.com/UndCover/PyramidStore/main/aar/pyramid-1011.aar" -O $CURRENT_DIR/$DIR/app/libs/pyramid.aar 78 | sed -i "/thunder.jar/a\ implementation files('libs@pyramid.aar')" $CURRENT_DIR/$DIR/app/build.gradle 79 | sed -i 's#@#\\#g' $CURRENT_DIR/$DIR/app/build.gradle 80 | sed -i 's#pyramid#\\pyramid#g' $CURRENT_DIR/$DIR/app/build.gradle 81 | echo "" >>$CURRENT_DIR/$DIR/app/proguard-rules.pro 82 | echo "" >>$CURRENT_DIR/$DIR/app/proguard-rules.pro 83 | echo "#添加PY支持" >>$CURRENT_DIR/$DIR/app/proguard-rules.pro 84 | echo "-keep public class com.undcover.freedom.pyramid.** { *; }" >>$CURRENT_DIR/$DIR/app/proguard-rules.pro 85 | echo "-dontwarn com.undcover.freedom.pyramid.**" >>$CURRENT_DIR/$DIR/app/proguard-rules.pro 86 | echo "-keep public class com.chaquo.python.** { *; }" >>$CURRENT_DIR/$DIR/app/proguard-rules.pro 87 | echo "-dontwarn com.chaquo.python.**" >>$CURRENT_DIR/$DIR/app/proguard-rules.pro 88 | sed -i '/import com.orhanobut.hawk.Hawk;/a\import com.undcover.freedom.pyramid.PythonLoader;' $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/base/App.java 89 | sed -i '/import com.orhanobut.hawk.Hawk;/a\import com.github.catvod.crawler.SpiderNull;' $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/base/App.java 90 | sed -i '/PlayerHelper.init/a\ PythonLoader.getInstance().setApplication(this);' $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/base/App.java 91 | sed -i '/import android.util.Base64;/a\import com.github.catvod.crawler.SpiderNull;' $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/api/ApiConfig.java 92 | sed -i '/import android.util.Base64;/a\import com.undcover.freedom.pyramid.PythonLoader;' $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/api/ApiConfig.java 93 | sed -i '/private void parseJson(String apiUrl, String jsonStr)/a\ PythonLoader.getInstance().setConfig(jsonStr);' $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/api/ApiConfig.java 94 | sed -i '/public Spider getCSP(SourceBean sourceBean)/a\ if (sourceBean.getApi().startsWith(\"py_\")) {\n try {\n return PythonLoader.getInstance().getSpider(sourceBean.getKey(), sourceBean.getExt());\n } catch (Exception e) {\n e.printStackTrace();\n return new SpiderNull();\n }\n }' $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/api/ApiConfig.java 95 | sed -i '/public Object\[\] proxyLoca/a\ try {\n if(param.containsKey(\"api\")){\n String doStr = param.get(\"do\").toString();\n if(doStr.equals(\"ck\"))\n return PythonLoader.getInstance().proxyLocal(\"\",\"\",param);\n SourceBean sourceBean = ApiConfig.get().getSource(doStr);\n return PythonLoader.getInstance().proxyLocal(sourceBean.getKey(),sourceBean.getExt(),param);\n }else{\n String doStr = param.get(\"do\").toString();\n if(doStr.equals(\"live\")) return PythonLoader.getInstance().proxyLocal(\"\",\"\",param);\n }\n } catch (Exception e) {\n e.printStackTrace();\n }\n' $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/api/ApiConfig.java 96 | #FongMi的jar支持 97 | echo "" >>$CURRENT_DIR/$DIR/app/proguard-rules.pro 98 | echo "-keep class com.google.gson.**{*;}" >>$CURRENT_DIR/$DIR/app/proguard-rules.pro 99 | 100 | 101 | echo 'DIY end' 102 | -------------------------------------------------------------------------------- /diy-T-Jar.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #获取目录 4 | CURRENT_DIR=$(cd $(dirname $0); pwd) 5 | num=$(find $CURRENT_DIR -name gradlew | awk -F"/" '{print NF-1}'| head -1) 6 | DIR=$(find $CURRENT_DIR -name gradlew | cut -d \/ -f$num | head -1) 7 | cd $DIR 8 | 9 | # 签名 10 | signingConfigs='ICAgIHNpZ25pbmdDb25maWdzIHtcCiAgICAgICAgaWYgKHByb2plY3QuaGFzUHJvcGVydHkoIlJFTEVBU0VfU1RPUkVfRklMRSIpKSB7XAogICAgICAgICAgICBteUNvbmZpZyB7XAogICAgICAgICAgICAgICAgc3RvcmVGaWxlIGZpbGUoUkVMRUFTRV9TVE9SRV9GSUxFKVwKICAgICAgICAgICAgICAgIHN0b3JlUGFzc3dvcmQgUkVMRUFTRV9TVE9SRV9QQVNTV09SRFwKICAgICAgICAgICAgICAgIGtleUFsaWFzIFJFTEVBU0VfS0VZX0FMSUFTXAogICAgICAgICAgICAgICAga2V5UGFzc3dvcmQgUkVMRUFTRV9LRVlfUEFTU1dPUkRcCiAgICAgICAgICAgICAgICB2MVNpZ25pbmdFbmFibGVkIHRydWVcCiAgICAgICAgICAgICAgICB2MlNpZ25pbmdFbmFibGVkIHRydWVcCiAgICAgICAgICAgICAgICBlbmFibGVWM1NpZ25pbmcgPSB0cnVlXAogICAgICAgICAgICAgICAgZW5hYmxlVjRTaWduaW5nID0gdHJ1ZVwKICAgICAgICAgICAgfVwKICAgICAgICB9XAogICAgfVwKXA==' 11 | signingConfig='ICAgICAgICAgICAgaWYgKHByb2plY3QuaGFzUHJvcGVydHkoIlJFTEVBU0VfU1RPUkVfRklMRSIpKSB7XAogICAgICAgICAgICAgICAgc2lnbmluZ0NvbmZpZyBzaWduaW5nQ29uZmlncy5teUNvbmZpZ1wKICAgICAgICAgICAgfVwK' 12 | signingConfigs="$(echo "$signingConfigs" |base64 -d )" 13 | signingConfig="$(echo "$signingConfig" |base64 -d )" 14 | sed -i -e "/defaultConfig {/i\\$signingConfigs " -e "/debug {/a\\$signingConfig " -e "/release {/a\\$signingConfig " $CURRENT_DIR/$DIR/app/build.gradle 15 | cp -f $CURRENT_DIR/DIY/TVBoxOSC.jks $CURRENT_DIR/$DIR/app/TVBoxOSC.jks 16 | cp -f $CURRENT_DIR/DIY/TVBoxOSC.jks $CURRENT_DIR/$DIR/TVBoxOSC.jks 17 | echo "" >>$CURRENT_DIR/$DIR/gradle.properties 18 | echo "RELEASE_STORE_FILE=./TVBoxOSC.jks" >>$CURRENT_DIR/$DIR/gradle.properties 19 | echo "RELEASE_KEY_ALIAS=TVBoxOSC" >>$CURRENT_DIR/$DIR/gradle.properties 20 | echo "RELEASE_STORE_PASSWORD=TVBoxOSC" >>$CURRENT_DIR/$DIR/gradle.properties 21 | echo "RELEASE_KEY_PASSWORD=TVBoxOSC" >>$CURRENT_DIR/$DIR/gradle.properties 22 | 23 | #名称修改 24 | sed -i 's/TVBox/糖果影视/g' $CURRENT_DIR/$DIR/app/src/main/res/values-zh/strings.xml 25 | sed -i 's/TVBox/糖果影视/g' $CURRENT_DIR/$DIR/app/src/main/res/values/strings.xml 26 | sed -i 's#"app_source"><#"app_source">https://framagit.org/zhoujck/config/-/raw/master/box<#g' $CURRENT_DIR/$DIR/app/src/main/res/values-zh/strings.xml 27 | 28 | #包名修改为西瓜视频 29 | sed -i 's/com.github.tvbox.osc.tk/com.ss.android.article.video/g' $CURRENT_DIR/$DIR/app/build.gradle 30 | 31 | 32 | #图标修改 33 | mv $CURRENT_DIR/DIY/app_icon.png $CURRENT_DIR/$DIR/app/src/main/res/drawable/app_icon.png 34 | sed -i 's/app_banner/app_icon/g' $CURRENT_DIR/$DIR/app/src/main/AndroidManifest.xml 35 | 36 | #背景修改 37 | #mv $CURRENT_DIR/DIY/app_bg_black.png $CURRENT_DIR/$DIR/app/src/main/res/drawable/app_bg.png 38 | 39 | # 主页UI调整 恢复老版;默认多行显示 40 | #cp $CURRENT_DIR/DIY/T/fragment_user.xml $CURRENT_DIR/$DIR/app/src/main/res/layout/fragment_user.xml 41 | 42 | # 主页增加每日一言/去除部分图标 43 | #cp $CURRENT_DIR/DIY/T/ApiConfig.java $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/api/ApiConfig.java 44 | #cp $CURRENT_DIR/DIY/T/activity_home.xml $CURRENT_DIR/$DIR/app/src/main/res/layout/activity_home.xml 45 | #cp $CURRENT_DIR/DIY/T/HomeActivity.java $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/ui/activity/HomeActivity.java 46 | 47 | # 默认设置修改 48 | #cp $CURRENT_DIR/DIY/T/App.java $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/base/App.java 49 | 50 | # 取消首页从通知栏位置布置 51 | #cp $CURRENT_DIR/DIY/T/BaseActivity.java $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/base/BaseActivity.java 52 | 53 | # 直播添加epg112114支持 54 | #cp $CURRENT_DIR/DIY/T/LivePlayActivity.java $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/ui/activity/LivePlayActivity.java 55 | 56 | # 搜索改为爱奇艺热词,支持首字母联想 57 | #cp $CURRENT_DIR/DIY/T/SearchActivity.java $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/ui/activity/SearchActivity.java 58 | 59 | #长按倍速修改为2 60 | #sed -i 's/3.0/2.0/g' $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/player/controller/VodController.java 61 | 62 | #FongMi的jar支持 63 | echo "" >>$CURRENT_DIR/$DIR/app/proguard-rules.pro 64 | echo "-keep class com.google.gson.**{*;}" >>$CURRENT_DIR/$DIR/app/proguard-rules.pro 65 | 66 | echo 'DIY end' 67 | -------------------------------------------------------------------------------- /diy-T.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #获取目录 4 | CURRENT_DIR=$(cd $(dirname $0); pwd) 5 | num=$(find $CURRENT_DIR -name gradlew | awk -F"/" '{print NF-1}'| head -1) 6 | DIR=$(find $CURRENT_DIR -name gradlew | cut -d \/ -f$num | head -1) 7 | cd $DIR 8 | #签名 9 | signingConfigs='ICAgIHNpZ25pbmdDb25maWdzIHtcCiAgICAgICAgaWYgKHByb2plY3QuaGFzUHJvcGVydHkoIlJFTEVBU0VfU1RPUkVfRklMRSIpKSB7XAogICAgICAgICAgICBteUNvbmZpZyB7XAogICAgICAgICAgICAgICAgc3RvcmVGaWxlIGZpbGUoUkVMRUFTRV9TVE9SRV9GSUxFKVwKICAgICAgICAgICAgICAgIHN0b3JlUGFzc3dvcmQgUkVMRUFTRV9TVE9SRV9QQVNTV09SRFwKICAgICAgICAgICAgICAgIGtleUFsaWFzIFJFTEVBU0VfS0VZX0FMSUFTXAogICAgICAgICAgICAgICAga2V5UGFzc3dvcmQgUkVMRUFTRV9LRVlfUEFTU1dPUkRcCiAgICAgICAgICAgICAgICB2MVNpZ25pbmdFbmFibGVkIHRydWVcCiAgICAgICAgICAgICAgICB2MlNpZ25pbmdFbmFibGVkIHRydWVcCiAgICAgICAgICAgICAgICBlbmFibGVWM1NpZ25pbmcgPSB0cnVlXAogICAgICAgICAgICAgICAgZW5hYmxlVjRTaWduaW5nID0gdHJ1ZVwKICAgICAgICAgICAgfVwKICAgICAgICB9XAogICAgfVwKXA==' 10 | signingConfig='ICAgICAgICAgICAgaWYgKHByb2plY3QuaGFzUHJvcGVydHkoIlJFTEVBU0VfU1RPUkVfRklMRSIpKSB7XAogICAgICAgICAgICAgICAgc2lnbmluZ0NvbmZpZyBzaWduaW5nQ29uZmlncy5teUNvbmZpZ1wKICAgICAgICAgICAgfVwK' 11 | signingConfigs="$(echo "$signingConfigs" |base64 -d )" 12 | signingConfig="$(echo "$signingConfig" |base64 -d )" 13 | sed -i -e "/defaultConfig {/i\\$signingConfigs " -e "/debug {/a\\$signingConfig " -e "/release {/a\\$signingConfig " $CURRENT_DIR/$DIR/app/build.gradle 14 | cp -f $CURRENT_DIR/DIY/TVBoxOSC.jks $CURRENT_DIR/$DIR/app/TVBoxOSC.jks 15 | cp -f $CURRENT_DIR/DIY/TVBoxOSC.jks $CURRENT_DIR/$DIR/TVBoxOSC.jks 16 | echo "" >>$CURRENT_DIR/$DIR/gradle.properties 17 | echo "RELEASE_STORE_FILE=./TVBoxOSC.jks" >>$CURRENT_DIR/$DIR/gradle.properties 18 | echo "RELEASE_KEY_ALIAS=TVBoxOSC" >>$CURRENT_DIR/$DIR/gradle.properties 19 | echo "RELEASE_STORE_PASSWORD=TVBoxOSC" >>$CURRENT_DIR/$DIR/gradle.properties 20 | echo "RELEASE_KEY_PASSWORD=TVBoxOSC" >>$CURRENT_DIR/$DIR/gradle.properties 21 | 22 | #名称修改 23 | sed -i 's/TVBox/糖果影视/g' $CURRENT_DIR/$DIR/app/src/main/res/values-zh/strings.xml 24 | sed -i 's/TVBox/糖果影视/g' $CURRENT_DIR/$DIR/app/src/main/res/values/strings.xml 25 | sed -i 's#"app_source"><#"app_source">https://gitee.com/zhoujck/tv/raw/master/box<#g' $CURRENT_DIR/$DIR/app/src/main/res/values-zh/strings.xml 26 | 27 | #图标修改 28 | mv $CURRENT_DIR/DIY/app_icon.png $CURRENT_DIR/$DIR/app/src/main/res/drawable/app_icon.png 29 | sed -i 's/app_banner/app_icon/g' $CURRENT_DIR/$DIR/app/src/main/AndroidManifest.xml 30 | 31 | 32 | #背景修改 33 | mv $CURRENT_DIR/DIY/app_bg_black.png $CURRENT_DIR/$DIR/app/src/main/res/drawable/app_bg.png 34 | 35 | # 主页UI调整 恢复老版;默认多行显示 36 | cp $CURRENT_DIR/DIY/T/fragment_user.xml $CURRENT_DIR/$DIR/app/src/main/res/layout/fragment_user.xml 37 | 38 | # 主页增加每日一言/去除部分图标 39 | cp $CURRENT_DIR/DIY/T/ApiConfig.java $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/api/ApiConfig.java 40 | cp $CURRENT_DIR/DIY/T/activity_home.xml $CURRENT_DIR/$DIR/app/src/main/res/layout/activity_home.xml 41 | cp $CURRENT_DIR/DIY/T/HomeActivity.java $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/ui/activity/HomeActivity.java 42 | 43 | # 默认设置修改 44 | cp $CURRENT_DIR/DIY/T/App.java $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/base/App.java 45 | 46 | # 整体布局修改 47 | cp $CURRENT_DIR/DIY/T/BaseActivity.java $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/base/BaseActivity.java 48 | 49 | # 直播添加epg112114支持 50 | cp $CURRENT_DIR/DIY/T/LivePlayActivity.java $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/ui/activity/LivePlayActivity.java 51 | 52 | # 搜索改为爱奇艺热词,支持首字母联想 53 | #cp $CURRENT_DIR/DIY/T/SearchActivity.java $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/ui/activity/SearchActivity.java 54 | 55 | #长按倍速修改为2 56 | sed -i 's/3.0/2.0/g' $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/player/controller/VodController.java 57 | 58 | #版本号修改 59 | sed -i 's/versionName "1.0."/versionName "1."/g' $CURRENT_DIR/$DIR/app/build.gradle 60 | 61 | #FongMi的jar支持 62 | echo "" >>$CURRENT_DIR/$DIR/app/proguard-rules.pro 63 | echo "-keep class com.google.gson.**{*;}" >>$CURRENT_DIR/$DIR/app/proguard-rules.pro 64 | 65 | #添加PY支持 66 | wget --no-check-certificate -qO- "https://raw.githubusercontent.com/UndCover/PyramidStore/main/aar/pyramid-1011.aar" -O $CURRENT_DIR/$DIR/app/libs/pyramid.aar 67 | sed -i "/thunder.jar/a\ implementation files('libs@pyramid.aar')" $CURRENT_DIR/$DIR/app/build.gradle 68 | sed -i 's#@#\\#g' $CURRENT_DIR/$DIR/app/build.gradle 69 | sed -i 's#pyramid#\\pyramid#g' $CURRENT_DIR/$DIR/app/build.gradle 70 | echo "" >>$CURRENT_DIR/$DIR/app/proguard-rules.pro 71 | echo "" >>$CURRENT_DIR/$DIR/app/proguard-rules.pro 72 | echo "#添加PY支持" >>$CURRENT_DIR/$DIR/app/proguard-rules.pro 73 | echo "-keep public class com.undcover.freedom.pyramid.** { *; }" >>$CURRENT_DIR/$DIR/app/proguard-rules.pro 74 | echo "-dontwarn com.undcover.freedom.pyramid.**" >>$CURRENT_DIR/$DIR/app/proguard-rules.pro 75 | echo "-keep public class com.chaquo.python.** { *; }" >>$CURRENT_DIR/$DIR/app/proguard-rules.pro 76 | echo "-dontwarn com.chaquo.python.**" >>$CURRENT_DIR/$DIR/app/proguard-rules.pro 77 | sed -i '/import com.orhanobut.hawk.Hawk;/a\import com.undcover.freedom.pyramid.PythonLoader;' $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/base/App.java 78 | sed -i '/import com.orhanobut.hawk.Hawk;/a\import com.github.catvod.crawler.SpiderNull;' $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/base/App.java 79 | sed -i '/PlayerHelper.init/a\ PythonLoader.getInstance().setApplication(this);' $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/base/App.java 80 | sed -i '/import android.util.Base64;/a\import com.github.catvod.crawler.SpiderNull;' $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/api/ApiConfig.java 81 | sed -i '/import android.util.Base64;/a\import com.undcover.freedom.pyramid.PythonLoader;' $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/api/ApiConfig.java 82 | sed -i '/private void parseJson(String apiUrl, String jsonStr)/a\ PythonLoader.getInstance().setConfig(jsonStr);' $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/api/ApiConfig.java 83 | sed -i '/public Spider getCSP(SourceBean sourceBean)/a\ if (sourceBean.getApi().startsWith(\"py_\")) {\n try {\n return PythonLoader.getInstance().getSpider(sourceBean.getKey(), sourceBean.getExt());\n } catch (Exception e) {\n e.printStackTrace();\n return new SpiderNull();\n }\n }' $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/api/ApiConfig.java 84 | sed -i '/public Object\[\] proxyLoca/a\ try {\n if(param.containsKey(\"api\")){\n String doStr = param.get(\"do\").toString();\n if(doStr.equals(\"ck\"))\n return PythonLoader.getInstance().proxyLocal(\"\",\"\",param);\n SourceBean sourceBean = ApiConfig.get().getSource(doStr);\n return PythonLoader.getInstance().proxyLocal(sourceBean.getKey(),sourceBean.getExt(),param);\n }else{\n String doStr = param.get(\"do\").toString();\n if(doStr.equals(\"live\")) return PythonLoader.getInstance().proxyLocal(\"\",\"\",param);\n }\n } catch (Exception e) {\n e.printStackTrace();\n }\n' $CURRENT_DIR/$DIR/app/src/main/java/com/github/tvbox/osc/api/ApiConfig.java 85 | 86 | 87 | echo 'DIY end' 88 | --------------------------------------------------------------------------------