精华内容
下载资源
问答
  • 现在很多用户保存文件都会选择保存到网盘,喜欢的音乐也是一样,网易云音乐早已引入了云盘功能,不过上传的方法相信有很多朋友都不知道,下面小编为大家带来网易云音乐把音乐上传云盘的步骤方法,感兴趣的朋友可以...

    现在很多用户保存文件都会选择保存到网盘,喜欢的音乐也是一样,网易云音乐早已引入了云盘功能,不过上传的方法相信有很多朋友都不知道,下面小编为大家带来网易云音乐把音乐上传到云盘的步骤方法,感兴趣的朋友可以进来了解下。

    4483c48b5cecb72205c9d0ed3370283f.png

    网易云音乐怎么把音乐上传到云盘

    打开网易云音乐,选取“我的音乐云盘”;

    b183e5609f82a3c7f2def89a3a41112c.png

    点击我的音乐云盘窗口内的“上传音乐”;

    59de0b9a795b053a029be3111c8aa21b.png

    在设备中找到欲上传的音乐,并按下“选择”按钮;

    247e3c38871add9aa7a7f3049abd3b0b.png

    之后,就可以在我的音乐云盘窗口看到它了。

    a8555778473f6f8d44e161e9f6df69b0.png

    网易云音乐怎样上传歌曲

    1、打开网易云音乐PC客户端,点击“本地音乐”,网易云会自动扫描电脑上的音乐,然后保存到云上。

    c499e834a35514cc89ad22a129ef6852.png

    2、也可以手动把音乐上传到音乐云盘中,音乐云盘有容量限制,等级LV.1容量为5G,最高LV.10,容量100G。

    3、在网易云音乐主界面点击“我的音乐云盘”中的“上传音乐”。

    cb30ff329f12115baf72080b151a6b80.png

    4、然后选中要上传的音乐,完成上传就可以了。

    9fca70ef6c6d9ea0f75edc1bafaec5be.png

    关于网易云音乐把音乐上传到云盘的步骤方法就分享到这了,希望可以给大家带来帮助,如果你还想了解更多关于驱动人生的使用教程,可以进入教程之家网查询了解。

    展开全文
  • Android 音乐APP(一)扫描本地音乐

    千次阅读 多人点赞 2020-10-14 15:32:54
    音乐APP 扫描本地音乐前言① 新建项目② 第三方依赖 前言   这个项目纯粹的就是心血来潮,打算写一个,写作的方式和天气APP类似,博客当成开发笔记吧,感兴趣可以跟着看,OK,新建一个项目。 ① 新建项目 写之前...

    效果图
    在这里插入图片描述

    前言

      这个项目纯粹的就是心血来潮,打算写一个,写作的方式和天气APP类似,把博客当成开发笔记吧,感兴趣可以跟着看,OK,新建一个项目。

    正文

    ① 新建项目

    写之前我就想好名字了,就叫GoodMusic,如下图创建项目
    在这里插入图片描述
    最低版本从6.0开始,然后点击Finish完成创建。

    ② 第三方依赖

    打开项目的build.gradle,新增依赖库

    		//新增
            maven { url "https://jitpack.io" }
            //新增
            mavenCentral()
    

    如下图
    在这里插入图片描述
    然后再打开app下面的build.gradle,现在android闭包中指定使用的JDK版本,和开启DataBinding的使用。
    在这里插入图片描述
    然后再dependencies闭包中,增加如下依赖:

    	//Google Material控件,以及迁移到AndroidX下一些控件的依赖
        implementation 'com.google.android.material:material:1.2.0'
        implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
        implementation 'androidx.annotation:annotation:1.1.0'
        implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    
        //RecyclerView最好的适配器,让你的适配器一目了然,告别代码冗余
        implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.30'
        //权限请求框架
        implementation 'com.permissionx.guolindev:permissionx:1.4.0'
    

    然后Sync同步一下。

    ③ 权限和基础配置

    从文章的标题可以得知,扫描本地音乐就是要打开手机的文件夹,是需要权限的,不光要在AndroidManifest.xml中注册,也要在打开的时候动态申请才行,因为这个是危险权限。
    打开AndroidManifest.xml,增加如下代码:

    	<!-- 文件读写权限  Android6.0 以后需要动态获取  10.0之后对文件的处理更复杂了 -->
        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />
        
    

    当然这还没有玩,因为我想过,我的这个APP不可能只有一个Activity,会有多个,所以就需要写一个管理Activity的类。
    下面在com.llw.goodmusic包下新建一个basic包,在该包下新建一个ActivityManager类,类的代码如下所示:

    package com.llw.goodmusic.basic;
    
    import android.app.Activity;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 管理所有的Activity
     *
     * @author llw
     */
    public class ActivityManager {
        /**
         * 保存所有创建的Activity
         */
        private List<Activity> allActivities = new ArrayList<>();
    
        /**
         * 添加Activity到管理器
         *
         * @param activity activity
         */
        public void addActivity(Activity activity) {
            if (activity != null) {
                allActivities.add(activity);
            }
        }
    
    
        /**
         * 从管理器移除Activity
         *
         * @param activity activity
         */
        public void removeActivity(Activity activity) {
            if (activity != null) {
                allActivities.remove(activity);
            }
        }
    
        /**
         * 关闭所有Activity
         */
        public void finishAll() {
            for (Activity activity : allActivities) {
                activity.finish();
            }
    
        }
    
        /**
         * 获取栈顶的Activity
         *
         * @return
         */
        public Activity getTaskTop() {
            return allActivities.get(allActivities.size() - 1);
        }
    }
    
    

    从方法的注释你就明白这个类是干嘛的了。当然光是有一个管理的还不够,还需要一个对工程进行控制的类。在basic包下在建一个BasicApplication,代码如下:

    package com.llw.goodmusic.basic;
    
    import android.app.Application;
    import android.content.Context;
    import android.content.res.Configuration;
    
    /**
     * 工程管理
     *
     * @author llw
     */
    public class BasicApplication extends Application {
        private static ActivityManager activityManager;
        private static BasicApplication application;
        private static Context context;
    
        @Override
        public void onCreate() {
            super.onCreate();
            //声明Activity管理
            activityManager = new ActivityManager();
            context = getApplicationContext();
            application = this;
        }
    
    
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
        }
    
    
        public static ActivityManager getActivityManager() {
            return activityManager;
        }
    
        /**
         * 内容提供器
         * @return
         */
        public static Context getContext() {
            return context;
        }
    
        public static BasicApplication getApplication() {
            return application;
        }
    }
    
    
    

    还差最后一个就是Activity的简单封装,写一个基础的Activity,然后让所有的Activity继承这个,同时实现里面的抽象方法。
    这里需要先定义一个接口,由这个基础Activity来实现,在basic下面新建一个UiCallBack接口。里面的代码如下:

    package com.llw.goodmusic.basic;
    
    import android.os.Bundle;
    
    /**
     * UI回调接口
     *
     * @author llw
     */
    public interface UiCallBack {
    
        /**
         * 初始化savedInstanceState
         *
         * @param savedInstanceState
         */
        void initBeforeView(Bundle savedInstanceState);
    
        /**
         * 初始化数据 相当于onCreate
         *
         * @param savedInstanceState
         */
        void initData(Bundle savedInstanceState);
    
        /**
         * 绑定布局
         *
         * @return
         */
        int getLayoutId();
    }
    
    

    里面的方法比较简单就是一个Activity所需要的基本的东西,初始化参数和布局。然后在basic下面新建一个抽象的BasicActivity。里面的代码如下:

    package com.llw.goodmusic.basic;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.view.View;
    
    import androidx.annotation.Nullable;
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.appcompat.widget.Toolbar;
    
    /**
     * 基础Activity
     *
     * @author llw
     */
    public abstract class BasicActivity extends AppCompatActivity implements UiCallBack {
        /**
         * 快速点击的时间间隔
         */
        private static final int FAST_CLICK_DELAY_TIME = 500;
        /**
         * 最后点击的时间
         */
        private static long lastClickTime;
        /**
         * 上下文参数
         */
        protected Activity context;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            initBeforeView(savedInstanceState);
            this.context = this;
    
            //添加继承这个BaseActivity的Activity
            BasicApplication.getActivityManager().addActivity(this);
            //绑定布局id
            if (getLayoutId() > 0) {
                setContentView(getLayoutId());
            }
            //初始化数据
            initData(savedInstanceState);
        }
    
        @Override
        public void initBeforeView(Bundle savedInstanceState) {
    
        }
    
        /**
         * 返回
         *
         * @param toolbar
         */
        protected void Back(Toolbar toolbar) {
            toolbar.setNavigationOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    context.finish();
                    if (!isFastClick()) {
                        context.finish();
                    }
                }
            });
        }
    
        /**
         * 两次点击间隔不能少于500ms  防止多次点击
         *
         * @return flag
         */
        protected static boolean isFastClick() {
            boolean flag = true;
            long currentClickTime = System.currentTimeMillis();
            if ((currentClickTime - lastClickTime) >= FAST_CLICK_DELAY_TIME) {
                flag = false;
            }
            lastClickTime = currentClickTime;
    
            return flag;
        }
    
    	/**
         * 消息提示
         *
         * @param llw
         */
        protected void show(CharSequence llw) {
            Toast.makeText(context, llw, Toast.LENGTH_SHORT).show();
        }
    }
    
    

    里面除了提供上下文参数以外,还有绑定布局的id,初始化参数等方法,还有一些需要在后面再增加。
    现在都搞定了然后在com.llw.goodmusic下创建一个MusicApplication然后继承BasicApplication。代码如下:

    package com.llw.goodmusic;
    
    import android.app.Activity;
    import android.content.Context;
    import android.content.res.Configuration;
    import android.os.Handler;
    
    import com.llw.goodmusic.basic.ActivityManager;
    import com.llw.goodmusic.basic.BasicApplication;
    
    /**
     * 项目管理
     *
     * @author llw
     */
    public class MusicApplication extends BasicApplication {
    
        /**
         * 应用实例
         */
        public static MusicApplication musicApplication;
        private static Context context;
        private static ActivityManager activityManager;
    
        public static Context getMyContext() {
            return musicApplication == null ? null : musicApplication.getApplicationContext();
        }
    
        private Handler myHandler;
    
        public Handler getMyHandler() {
            return myHandler;
        }
    
        public void setMyHandler(Handler handler) {
            myHandler = handler;
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
    
            activityManager = new ActivityManager();
            context = getApplicationContext();
            musicApplication = this;
            
        }
    
    
        public static ActivityManager getActivityManager() {
            return activityManager;
        }
    
    
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
        }
    
    
    }
    
    
    

    还差最后一步配置,那就是在AndroidManifest.xml设置MusicApplication

    在这里插入图片描述
    然后再改一下styles.xml中的样式
    在这里插入图片描述
    里面colors.xml

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <color name="colorPrimary">#26252B</color>
        <color name="colorPrimaryDark">#26252B</color>
        <color name="colorAccent">#D81B60</color>
    
        <!--App主要颜色-->
        <color name="app_color">#26252B</color>
        <!--App背景颜色-->
        <color name="app_bg">#333439</color>
    
        <color name="white">#FFFFFF</color>
        <color name="white_2">#22FFFFFF</color><!--白色透明度22%-->
        <color name="white_4">#44FFFFFF</color><!--白色透明度44%-->
        <color name="white_6">#66FFFFFF</color><!--白色透明度66%-->
        <color name="white_8">#88FFFFFF</color><!--白色透明度88%-->
        <color name="transparent">#00000000</color><!--透明-->
    
        <color name="gold_color">#FF9D00</color>
    
    </resources>
    
    

    ④ 页面设计

    在这里插入图片描述
    这个图就是APP的主页面了,深色为主,下面来看这个怎么来写。图标可以去自己下载,也可以在源码中去拿,都行。下面看看activity_main.xml的布局内容

    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/app_bg"
            android:orientation="vertical"
            tools:context=".ui.MainActivity">
    
            <!--标题-->
            <TextView
                android:id="@+id/tv_title"
                android:gravity="center"
                android:layout_width="match_parent"
                android:layout_gravity="center"
                android:text="Good Music"
                android:layout_height="?attr/actionBarSize"
                android:background="@color/app_color"
                android:textColor="@color/white"
                android:textSize="@dimen/sp_18" />
    
            <!--主要操作区域-->
            <LinearLayout
    
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical"
                android:padding="@dimen/dp_12">
    
                <!--本地音乐-->
                <LinearLayout
                    android:onClick="onClick"
                    android:id="@+id/lay_local_music"
                    android:layout_width="@dimen/dp_120"
                    android:layout_height="@dimen/dp_120"
                    android:background="@drawable/shape_app_color_radius_5"
                    android:foreground="?android:attr/selectableItemBackground"
                    android:gravity="center"
                    android:orientation="vertical">
    
                    <ImageView
                        android:layout_width="@dimen/dp_48"
                        android:layout_height="@dimen/dp_48"
                        android:src="@mipmap/icon_local" />
    
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="@dimen/dp_8"
                        android:text="本地音乐"
                        android:textColor="@color/white"
                        android:textSize="@dimen/sp_16" />
                </LinearLayout>
    
            </LinearLayout>
        </LinearLayout>
    </layout>
    

    然后当然是要在MainActivity中做处理了。

    package com.llw.goodmusic.ui;
    
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.View;
    
    import com.llw.goodmusic.R;
    import com.llw.goodmusic.basic.BasicActivity;
    
    /**
     * 主页面
     *
     * @author llw
     */
    public class MainActivity extends BasicActivity {
    
    
        @Override
        public void initData(Bundle savedInstanceState) {
    
        }
    
        @Override
        public int getLayoutId() {
            return R.layout.activity_main;
        }
    
        public void onClick(View view) {
            startActivity(new Intent(context,LocalMusicActivity.class));
        }
    }
    
    

    里面的代码也比较的简单,继承BasicActivity。然后重写initData和getLayoutId,再绑定布局中的onclick就可以了。那么它要跳转到LocalMusicActivity。这个Activity现在还没有的,那就创建一个。创建好了之后同样继承BasicActivity,重写里面的两个方法,绑定布局之后,下面来写这个页面的布局。activity_local_music.xml代码如下:

    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/app_bg"
            android:orientation="vertical"
            tools:context=".ui.MainActivity">
            <!--Toolbar-->
            <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="@color/app_color"
                app:navigationIcon="@mipmap/icon_return_white">
    
                <TextView
                    android:id="@+id/tv_title"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:text="本地音乐"
                    android:textColor="@color/white"
                    android:textSize="@dimen/sp_18" />
    
            </androidx.appcompat.widget.Toolbar>
    
            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent">
                <!--扫描音乐布局-->
                <LinearLayout
                    android:id="@+id/lay_scan_music"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:gravity="center"
                    android:orientation="vertical">
    
                    <ImageView
                        android:layout_width="@dimen/dp_140"
                        android:layout_height="@dimen/dp_140"
                        android:src="@mipmap/icon_empty" />
                    <!--扫描本地音乐-->
                    <com.google.android.material.button.MaterialButton
                        style="@style/Widget.MaterialComponents.Button.UnelevatedButton"
                        android:layout_width="@dimen/dp_140"
                        android:layout_height="@dimen/dp_40"
                        android:layout_marginTop="@dimen/dp_16"
                        android:insetTop="@dimen/dp_0"
                        android:insetBottom="@dimen/dp_0"
                        android:onClick="scanLocalMusic"
                        android:text="扫描本地音乐"
                        android:textSize="@dimen/sp_14"
                        android:theme="@style/Theme.MaterialComponents.Light.NoActionBar"
                        app:backgroundTint="@color/transparent"
                        app:cornerRadius="@dimen/dp_20"
                        app:strokeColor="@color/white"
                        app:strokeWidth="@dimen/dp_1" />
                </LinearLayout>
                <!--列表-->
                <androidx.recyclerview.widget.RecyclerView
                    android:id="@+id/rv_music"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />
            </RelativeLayout>
        </LinearLayout>
    </layout>
    

    里面有两个布局,一个是用来扫描本地歌曲的,一个是用来显示歌曲的列表,如果扫描不到就提示一下。现在页面的布局有了,下面就是要来写这个页面的业务逻辑。

    ⑤ 权限请求

    之前在AndroidManifest.xml中注册了静态的文件读写权限,而在Android 6.0之后。危险权限需要动态申请才能够使用。所以我在build.gradle中增加了一个权限请求框架,现在就来使用吧。

    	/**
         * 动态权限请求
         */
        private void permissionsRequest() {
    
            PermissionX.init(this).permissions(
                    //写入文件
                    Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    .onExplainRequestReason(new ExplainReasonCallbackWithBeforeParam() {
                        @Override
                        public void onExplainReason(ExplainScope scope, List<String> deniedList, boolean beforeRequest) {
                            scope.showRequestReasonDialog(deniedList, "即将申请的权限是程序必须依赖的权限", "我已明白");
                        }
                    })
                    .onForwardToSettings(new ForwardToSettingsCallback() {
                        @Override
                        public void onForwardToSettings(ForwardScope scope, List<String> deniedList) {
                            scope.showForwardToSettingsDialog(deniedList, "您需要去应用程序设置当中手动开启权限", "我已明白");
                        }
                    })
                    .setDialogTintColor(R.color.white, R.color.app_color)
                    .request(new RequestCallback() {
                        @Override
                        public void onResult(boolean allGranted, List<String> grantedList, List<String> deniedList) {
                            if (allGranted) {
                                //通过后的业务逻辑
                            } else {
                                show("您拒绝了如下权限:" + deniedList);
                            }
                        }
                    });
        }
    

    OK,权限申请就是这么简单。

    ⑥ 获取音乐数据

    首先需要些几个工具类,方便APP后面的开发。第一个是日志,这里不用系统自带的日志。在utils包下新建一个BLog类。里面的代码如下:

    package com.llw.goodmusic.utils;
    
    import android.text.TextUtils;
    import android.util.Log;
    
    import org.json.JSONArray;
    import org.json.JSONException;
    import org.json.JSONObject;
    
    /**
     * 日志
     *
     * @author llw
     */
    public class BLog {
    
        private static boolean IS_SHOW_LOG = true;
    
        private static final String DEFAULT_MESSAGE = "execute";
        private static final String LINE_SEPARATOR = System.getProperty("line.separator");
        private static final int JSON_INDENT = 4;
    
        private static final int V = 0x1;
        private static final int D = 0x2;
        private static final int I = 0x3;
        private static final int W = 0x4;
        private static final int E = 0x5;
        private static final int A = 0x6;
        private static final int JSON = 0x7;
    
        public static void init(boolean isShowLog) {
            IS_SHOW_LOG = isShowLog;
        }
    
        public static void v() {
            printLog(V, null, DEFAULT_MESSAGE);
        }
    
        public static void v(String msg) {
            printLog(V, null, msg);
        }
    
        public static void v(String tag, String msg) {
            printLog(V, tag, msg);
        }
    
        public static void d() {
            printLog(D, null, DEFAULT_MESSAGE);
        }
    
        public static void d(String msg) {
            printLog(D, null, msg);
        }
    
        public static void d(String tag, String msg) {
            printLog(D, tag, msg);
        }
    
        public static void i() {
            printLog(I, null, DEFAULT_MESSAGE);
        }
    
        public static void i(String msg) {
            printLog(I, null, msg);
        }
    
        public static void i(String tag, String msg) {
            printLog(I, tag, msg);
        }
    
        public static void w() {
            printLog(W, null, DEFAULT_MESSAGE);
        }
    
        public static void w(String msg) {
            printLog(W, null, msg);
        }
    
        public static void w(String tag, String msg) {
            printLog(W, tag, msg);
        }
    
        public static void e() {
            printLog(E, null, DEFAULT_MESSAGE);
        }
    
        public static void e(String msg) {
            printLog(E, null, msg);
        }
    
        public static void e(String tag, String msg) {
            printLog(E, tag, msg);
        }
    
        public static void a() {
            printLog(A, null, DEFAULT_MESSAGE);
        }
    
        public static void a(String msg) {
            printLog(A, null, msg);
        }
    
        public static void a(String tag, String msg) {
            printLog(A, tag, msg);
        }
    
    
        public static void json(String jsonFormat) {
            printLog(JSON, null, jsonFormat);
        }
    
        public static void json(String tag, String jsonFormat) {
            printLog(JSON, tag, jsonFormat);
        }
    
    
        private static void printLog(int type, String tagStr, String msg) {
    
            if (!IS_SHOW_LOG) {
                return;
            }
    
            StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
    
            int index = 4;
            String className = stackTrace[index].getFileName();
            String methodName = stackTrace[index].getMethodName();
            int lineNumber = stackTrace[index].getLineNumber();
    
            String tag = (tagStr == null ? className : tagStr);
            methodName = methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
    
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append("[ (").append(className).append(":").append(lineNumber).append(")#").append(methodName).append(" ] ");
    
            if (msg != null && type != JSON) {
                stringBuilder.append(msg);
            }
    
            String logStr = stringBuilder.toString();
    
            switch (type) {
                case V:
                    Log.v(tag, logStr);
                    break;
                case D:
                    Log.d(tag, logStr);
                    break;
                case I:
                    Log.i(tag, logStr);
                    break;
                case W:
                    Log.w(tag, logStr);
                    break;
                case E:
                    Log.e(tag, logStr);
                    break;
                case A:
                    Log.wtf(tag, logStr);
                    break;
                case JSON: {
    
                    if (TextUtils.isEmpty(msg)) {
                        Log.d(tag, "Empty or Null json content");
                        return;
                    }
    
                    String message = null;
    
                    try {
                        if (msg.startsWith("{")) {
                            JSONObject jsonObject = new JSONObject(msg);
                            message = jsonObject.toString(JSON_INDENT);
                        } else if (msg.startsWith("[")) {
                            JSONArray jsonArray = new JSONArray(msg);
                            message = jsonArray.toString(JSON_INDENT);
                        }
                    } catch (JSONException e) {
                        e(tag, e.getCause().getMessage() + "\n" + msg);
                        return;
                    }
    
                    printLine(tag, true);
                    message = logStr + LINE_SEPARATOR + message;
                    String[] lines = message.split(LINE_SEPARATOR);
                    StringBuilder jsonContent = new StringBuilder();
                    for (String line : lines) {
                        jsonContent.append("║ ").append(line).append(LINE_SEPARATOR);
                    }
                    Log.d(tag, jsonContent.toString());
                    printLine(tag, false);
                }
                break;
                default:
                    break;
            }
    
        }
    
        private static void printLine(String tag, boolean isTop) {
            if (isTop) {
                Log.d(tag, "╔═══════════════════════════════════════════════════════════════════════════════════════");
            } else {
                Log.d(tag, "╚═══════════════════════════════════════════════════════════════════════════════════════");
            }
        }
    
    }
    
    

    为了方便使用,我再加上一个ToastUtils,代码如下:

    package com.llw.goodmusic.utils;
    
    import android.content.Context;
    import android.widget.Toast;
    
    public class ToastUtils {
        /**
         * 长消息
         *
         * @param context 上下文参数
         * @param llw     内容
         */
        public static void longToast(Context context, CharSequence llw) {
            Toast.makeText(context.getApplicationContext(), llw, Toast.LENGTH_LONG).show();
        }
    
        /**
         * 短消息
         *
         * @param context 上下文参数
         * @param llw     内容
         */
        public static void shortToast(Context context, CharSequence llw) {
            Toast.makeText(context.getApplicationContext(), llw, Toast.LENGTH_SHORT).show();
        }
    }
    
    

    既然是歌曲信息肯定是需要一个实体bean的。在com.llw.goodmusic下新建一个bean包。在包下新建一个Song类,代码如下:

    package com.llw.goodmusic.bean;
    
    /**
     * 歌曲Bean
     *
     * @author llw
     */
    public class Song {
        /**
         * 歌手
         */
        public String singer;
        /**
         * 歌曲名
         */
        public String song;
        /**
         * 专辑名
         */
        public String album;
        /**
         * 专辑图片
         */
        public String album_art;
        /**
         * 歌曲的地址
         */
        public String path;
        /**
         * 歌曲长度
         */
        public int duration;
        /**
         * 歌曲的大小
         */
        public long size;
        /**
         * 当前歌曲选中
         */
        public boolean isCheck;
    
        public String getSinger() {
            return singer;
        }
    
        public void setSinger(String singer) {
            this.singer = singer;
        }
    
        public String getSong() {
            return song;
        }
    
        public void setSong(String song) {
            this.song = song;
        }
    
        public String getPath() {
            return path;
        }
    
        public void setPath(String path) {
            this.path = path;
        }
    
        public int getDuration() {
            return duration;
        }
    
        public void setDuration(int duration) {
            this.duration = duration;
        }
    
        public long getSize() {
            return size;
        }
    
        public void setSize(long size) {
            this.size = size;
        }
    
        public String getAlbum() {
            return album;
        }
    
        public void setAlbum(String album) {
            this.album = album;
        }
    
        public String getAlbum_art() {
            return album_art;
        }
    
        public void setAlbum_art(String album_art) {
            this.album_art = album_art;
        }
    
        public boolean isCheck() {
            return isCheck;
        }
    
        public void setCheck(boolean check) {
            isCheck = check;
        }
    }
    
    

    然后还有一个最主要的工具类MusicUtils,代码如下:

    package com.llw.goodmusic.utils;
    
    import android.content.Context;
    import android.database.Cursor;
    import android.provider.MediaStore;
    
    import com.llw.goodmusic.bean.Song;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 音乐扫描工具
     *
     * @author llw
     */
    public class MusicUtils {
        /**
         * 扫描系统里面的音频文件,返回一个list集合
         */
        public static List<Song> getMusicData(Context context) {
            List<Song> list = new ArrayList<Song>();
            // 媒体库查询语句(写一个工具类MusicUtils)
            Cursor cursor = context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null,
                    null, MediaStore.Audio.Media.IS_MUSIC);
            if (cursor != null) {
                while (cursor.moveToNext()) {
                    Song song = new Song();
                    //歌曲名称
                    song.song = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));
                    //歌手
                    song.singer = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
                    //专辑名
                    song.album = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));
                    //歌曲路径
                    song.path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));
                    //歌曲时长
                    song.duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION));
                    //歌曲大小
                    song.size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE));
    
                    if (song.size > 1000 * 800) {
                        // 注释部分是切割标题,分离出歌曲名和歌手 (本地媒体库读取的歌曲信息不规范)
                        if (song.song.contains("-")) {
                            String[] str = song.song.split("-");
                            song.singer = str[0];
                            song.song = str[1];
                        }
                        list.add(song);
                    }
                }
                // 释放资源
                cursor.close();
            }
            return list;
        }
    
    }
    

      这个扫描请求的工具类是无法扫描到加密的音乐文件的,能扫描到mp3、flac格式的音乐文件,其他的格式我没有试过,因为现在网易云和QQ音乐下载本地歌曲有很多是需要VIP才能下载的,这种音乐下载之后是加密的音乐文件,QQ音乐的下载的加密文件是 .qmc后缀开头的,网易的我就不知道了,因为我没有开网易云音乐的VIP,不过这些加密文件有一个共同点,不允许其他播放器播放,这个就很恶心了,也就是说哪怕你通过文件夹路径扫描到添加到你自己的音乐播放列表里面之后也播放不了。因为加密规则你不知道,你就不能去解密,解密不了自然播放不了。

    最终你的项目目录会如下图所示
    在这里插入图片描述
    如果有出入的话可以照这个来改一下,或者可以自己分包也可以。

    ⑦ 数据显示

    做一个列表来显示本地的歌曲列表,列表由item决定,item需要新建一个xml文件,如下图这种。
    在这里插入图片描述
    在layout下面新建一个item_music_rv_list.xml,布局如下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/item_music"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="@dimen/dp_1"
        android:background="@color/app_color"
        android:foreground="?android:attr/selectableItemBackground"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        android:padding="@dimen/dp_10">
    
        <TextView
            android:id="@+id/tv_position"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="2dp"
            android:text="1"
            android:textColor="@color/white"
            android:textSize="@dimen/sp_16" />
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="@dimen/dp_10"
            android:orientation="vertical">
    
            <TextView
                android:id="@+id/tv_song_name"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:maxLines="1"
                android:text="歌曲名"
                android:textColor="@color/white"
                android:textSize="@dimen/sp_18" />
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="@dimen/dp_4">
    
                <TextView
                    android:id="@+id/tv_singer"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:ellipsize="end"
                    android:maxLines="1"
                    android:text="歌手"
                    android:textColor="@color/white"
                    android:textSize="@dimen/sp_14" />
    
                <TextView
                    android:id="@+id/tv_duration_time"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="12dp"
                    android:text="时间"
                    android:textColor="@color/white"
                    android:textSize="@dimen/sp_14" />
            </LinearLayout>
        </LinearLayout>
    </LinearLayout>
    

    里面的尺寸都是放在dimen.xml文件里面的,放在values.xml下,和colors.xml同级,这个我也贴一下代码

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <!--尺寸-->
        <dimen name="dp_0">0dp</dimen>
        <dimen name="dp_0_1">0.1dp</dimen>
        <dimen name="dp_0_5">0.5dp</dimen>
        <dimen name="dp_1">1dp</dimen>
        <dimen name="dp_1_5">1.5dp</dimen>
        <dimen name="dp_2">2dp</dimen>
        <dimen name="dp_2_5">2.5dp</dimen>
        <dimen name="dp_3">3dp</dimen>
        <dimen name="dp_3_5">3.5dp</dimen>
        <dimen name="dp_4">4dp</dimen>
        <dimen name="dp_4_5">4.5dp</dimen>
        <dimen name="dp_5">5dp</dimen>
        <dimen name="dp_6">6dp</dimen>
        <dimen name="dp_7">7dp</dimen>
        <dimen name="dp_8">8dp</dimen>
        <dimen name="dp_9">9dp</dimen>
        <dimen name="dp_10">10dp</dimen>
        <dimen name="dp_11">11dp</dimen>
        <dimen name="dp_12">12dp</dimen>
        <dimen name="dp_13">13dp</dimen>
        <dimen name="dp_14">14dp</dimen>
        <dimen name="dp_15">15dp</dimen>
        <dimen name="dp_16">16dp</dimen>
        <dimen name="dp_17">17dp</dimen>
        <dimen name="dp_18">18dp</dimen>
        <dimen name="dp_19">19dp</dimen>
        <dimen name="dp_20">20dp</dimen>
        <dimen name="dp_21">21dp</dimen>
        <dimen name="dp_22">22dp</dimen>
        <dimen name="dp_23">23dp</dimen>
        <dimen name="dp_24">24dp</dimen>
        <dimen name="dp_25">25dp</dimen>
        <dimen name="dp_26">26dp</dimen>
        <dimen name="dp_27">27dp</dimen>
        <dimen name="dp_28">28dp</dimen>
        <dimen name="dp_29">29dp</dimen>
        <dimen name="dp_30">30dp</dimen>
        <dimen name="dp_31">31dp</dimen>
        <dimen name="dp_32">32dp</dimen>
        <dimen name="dp_33">33dp</dimen>
        <dimen name="dp_34">34dp</dimen>
        <dimen name="dp_35">35dp</dimen>
        <dimen name="dp_36">36dp</dimen>
        <dimen name="dp_37">37dp</dimen>
        <dimen name="dp_38">38dp</dimen>
        <dimen name="dp_39">39dp</dimen>
        <dimen name="dp_40">40dp</dimen>
        <dimen name="dp_41">41dp</dimen>
        <dimen name="dp_42">42dp</dimen>
        <dimen name="dp_43">43dp</dimen>
        <dimen name="dp_44">44dp</dimen>
        <dimen name="dp_45">45dp</dimen>
        <dimen name="dp_46">46dp</dimen>
        <dimen name="dp_47">47dp</dimen>
        <dimen name="dp_48">48dp</dimen>
        <dimen name="dp_49">49dp</dimen>
        <dimen name="dp_50">50dp</dimen>
        <dimen name="dp_51">51dp</dimen>
        <dimen name="dp_52">52dp</dimen>
        <dimen name="dp_53">53dp</dimen>
        <dimen name="dp_54">54dp</dimen>
        <dimen name="dp_55">55dp</dimen>
        <dimen name="dp_56">56dp</dimen>
        <dimen name="dp_57">57dp</dimen>
        <dimen name="dp_58">58dp</dimen>
        <dimen name="dp_59">59dp</dimen>
        <dimen name="dp_60">60dp</dimen>
        <dimen name="dp_61">61dp</dimen>
        <dimen name="dp_62">62dp</dimen>
        <dimen name="dp_63">63dp</dimen>
        <dimen name="dp_64">64dp</dimen>
        <dimen name="dp_65">65dp</dimen>
        <dimen name="dp_66">66dp</dimen>
        <dimen name="dp_67">67dp</dimen>
        <dimen name="dp_68">68dp</dimen>
        <dimen name="dp_69">69dp</dimen>
        <dimen name="dp_70">70dp</dimen>
        <dimen name="dp_71">71dp</dimen>
        <dimen name="dp_72">72dp</dimen>
        <dimen name="dp_73">73dp</dimen>
        <dimen name="dp_74">74dp</dimen>
        <dimen name="dp_75">75dp</dimen>
        <dimen name="dp_76">76dp</dimen>
        <dimen name="dp_77">77dp</dimen>
        <dimen name="dp_78">78dp</dimen>
        <dimen name="dp_79">79dp</dimen>
        <dimen name="dp_80">80dp</dimen>
        <dimen name="dp_81">81dp</dimen>
        <dimen name="dp_82">82dp</dimen>
        <dimen name="dp_83">83dp</dimen>
        <dimen name="dp_84">84dp</dimen>
        <dimen name="dp_85">85dp</dimen>
        <dimen name="dp_86">86dp</dimen>
        <dimen name="dp_87">87dp</dimen>
        <dimen name="dp_88">88dp</dimen>
        <dimen name="dp_89">89dp</dimen>
        <dimen name="dp_90">90dp</dimen>
        <dimen name="dp_91">91dp</dimen>
        <dimen name="dp_92">92dp</dimen>
        <dimen name="dp_93">93dp</dimen>
        <dimen name="dp_94">94dp</dimen>
        <dimen name="dp_95">95dp</dimen>
        <dimen name="dp_96">96dp</dimen>
        <dimen name="dp_97">97dp</dimen>
        <dimen name="dp_98">98dp</dimen>
        <dimen name="dp_99">99dp</dimen>
        <dimen name="dp_100">100dp</dimen>
        <dimen name="dp_101">101dp</dimen>
        <dimen name="dp_102">102dp</dimen>
        <dimen name="dp_103">103dp</dimen>
        <dimen name="dp_104">104dp</dimen>
        <dimen name="dp_105">105dp</dimen>
        <dimen name="dp_106">106dp</dimen>
        <dimen name="dp_107">107dp</dimen>
        <dimen name="dp_108">108dp</dimen>
        <dimen name="dp_109">109dp</dimen>
        <dimen name="dp_110">110dp</dimen>
        <dimen name="dp_111">111dp</dimen>
        <dimen name="dp_112">112dp</dimen>
        <dimen name="dp_113">113dp</dimen>
        <dimen name="dp_114">114dp</dimen>
        <dimen name="dp_115">115dp</dimen>
        <dimen name="dp_116">116dp</dimen>
        <dimen name="dp_117">117dp</dimen>
        <dimen name="dp_118">118dp</dimen>
        <dimen name="dp_119">119dp</dimen>
        <dimen name="dp_120">120dp</dimen>
        <dimen name="dp_121">121dp</dimen>
        <dimen name="dp_122">122dp</dimen>
        <dimen name="dp_123">123dp</dimen>
        <dimen name="dp_124">124dp</dimen>
        <dimen name="dp_125">125dp</dimen>
        <dimen name="dp_126">126dp</dimen>
        <dimen name="dp_127">127dp</dimen>
        <dimen name="dp_128">128dp</dimen>
        <dimen name="dp_129">129dp</dimen>
        <dimen name="dp_130">130dp</dimen>
        <dimen name="dp_131">131dp</dimen>
        <dimen name="dp_132">132dp</dimen>
        <dimen name="dp_133">133dp</dimen>
        <dimen name="dp_134">134dp</dimen>
        <dimen name="dp_135">135dp</dimen>
        <dimen name="dp_136">136dp</dimen>
        <dimen name="dp_137">137dp</dimen>
        <dimen name="dp_138">138dp</dimen>
        <dimen name="dp_139">139dp</dimen>
        <dimen name="dp_140">140dp</dimen>
        <dimen name="dp_141">141dp</dimen>
        <dimen name="dp_142">142dp</dimen>
        <dimen name="dp_143">143dp</dimen>
        <dimen name="dp_144">144dp</dimen>
        <dimen name="dp_145">145dp</dimen>
        <dimen name="dp_146">146dp</dimen>
        <dimen name="dp_147">147dp</dimen>
        <dimen name="dp_148">148dp</dimen>
        <dimen name="dp_149">149dp</dimen>
        <dimen name="dp_150">150dp</dimen>
        <dimen name="dp_151">151dp</dimen>
        <dimen name="dp_152">152dp</dimen>
        <dimen name="dp_153">153dp</dimen>
        <dimen name="dp_154">154dp</dimen>
        <dimen name="dp_155">155dp</dimen>
        <dimen name="dp_156">156dp</dimen>
        <dimen name="dp_157">157dp</dimen>
        <dimen name="dp_158">158dp</dimen>
        <dimen name="dp_159">159dp</dimen>
        <dimen name="dp_160">160dp</dimen>
        <dimen name="dp_161">161dp</dimen>
        <dimen name="dp_162">162dp</dimen>
        <dimen name="dp_163">163dp</dimen>
        <dimen name="dp_164">164dp</dimen>
        <dimen name="dp_165">165dp</dimen>
        <dimen name="dp_166">166dp</dimen>
        <dimen name="dp_167">167dp</dimen>
        <dimen name="dp_168">168dp</dimen>
        <dimen name="dp_169">169dp</dimen>
        <dimen name="dp_170">170dp</dimen>
        <dimen name="dp_171">171dp</dimen>
        <dimen name="dp_172">172dp</dimen>
        <dimen name="dp_173">173dp</dimen>
        <dimen name="dp_174">174dp</dimen>
        <dimen name="dp_175">175dp</dimen>
        <dimen name="dp_176">176dp</dimen>
        <dimen name="dp_177">177dp</dimen>
        <dimen name="dp_178">178dp</dimen>
        <dimen name="dp_179">179dp</dimen>
        <dimen name="dp_180">180dp</dimen>
        <dimen name="dp_181">181dp</dimen>
        <dimen name="dp_182">182dp</dimen>
        <dimen name="dp_183">183dp</dimen>
        <dimen name="dp_184">184dp</dimen>
        <dimen name="dp_185">185dp</dimen>
        <dimen name="dp_186">186dp</dimen>
        <dimen name="dp_187">187dp</dimen>
        <dimen name="dp_188">188dp</dimen>
        <dimen name="dp_189">189dp</dimen>
        <dimen name="dp_190">190dp</dimen>
        <dimen name="dp_191">191dp</dimen>
        <dimen name="dp_192">192dp</dimen>
        <dimen name="dp_193">193dp</dimen>
        <dimen name="dp_194">194dp</dimen>
        <dimen name="dp_195">195dp</dimen>
        <dimen name="dp_196">196dp</dimen>
        <dimen name="dp_197">197dp</dimen>
        <dimen name="dp_198">198dp</dimen>
        <dimen name="dp_199">199dp</dimen>
        <dimen name="dp_200">200dp</dimen>
        <dimen name="dp_201">201dp</dimen>
        <dimen name="dp_202">202dp</dimen>
        <dimen name="dp_203">203dp</dimen>
        <dimen name="dp_204">204dp</dimen>
        <dimen name="dp_205">205dp</dimen>
        <dimen name="dp_206">206dp</dimen>
        <dimen name="dp_207">207dp</dimen>
        <dimen name="dp_208">208dp</dimen>
        <dimen name="dp_209">209dp</dimen>
        <dimen name="dp_210">210dp</dimen>
        <dimen name="dp_211">211dp</dimen>
        <dimen name="dp_212">212dp</dimen>
        <dimen name="dp_213">213dp</dimen>
        <dimen name="dp_214">214dp</dimen>
        <dimen name="dp_215">215dp</dimen>
        <dimen name="dp_216">216dp</dimen>
        <dimen name="dp_217">217dp</dimen>
        <dimen name="dp_218">218dp</dimen>
        <dimen name="dp_219">219dp</dimen>
        <dimen name="dp_220">220dp</dimen>
        <dimen name="dp_221">221dp</dimen>
        <dimen name="dp_222">222dp</dimen>
        <dimen name="dp_223">223dp</dimen>
        <dimen name="dp_224">224dp</dimen>
        <dimen name="dp_225">225dp</dimen>
        <dimen name="dp_226">226dp</dimen>
        <dimen name="dp_227">227dp</dimen>
        <dimen name="dp_228">228dp</dimen>
        <dimen name="dp_229">229dp</dimen>
        <dimen name="dp_230">230dp</dimen>
        <dimen name="dp_231">231dp</dimen>
        <dimen name="dp_232">232dp</dimen>
        <dimen name="dp_233">233dp</dimen>
        <dimen name="dp_234">234dp</dimen>
        <dimen name="dp_235">235dp</dimen>
        <dimen name="dp_236">236dp</dimen>
        <dimen name="dp_237">237dp</dimen>
        <dimen name="dp_238">238dp</dimen>
        <dimen name="dp_239">239dp</dimen>
        <dimen name="dp_240">240dp</dimen>
        <dimen name="dp_241">241dp</dimen>
        <dimen name="dp_242">242dp</dimen>
        <dimen name="dp_243">243dp</dimen>
        <dimen name="dp_244">244dp</dimen>
        <dimen name="dp_245">245dp</dimen>
        <dimen name="dp_246">246dp</dimen>
        <dimen name="dp_247">247dp</dimen>
        <dimen name="dp_248">248dp</dimen>
        <dimen name="dp_249">249dp</dimen>
        <dimen name="dp_250">250dp</dimen>
        <dimen name="dp_251">251dp</dimen>
        <dimen name="dp_252">252dp</dimen>
        <dimen name="dp_253">253dp</dimen>
        <dimen name="dp_254">254dp</dimen>
        <dimen name="dp_255">255dp</dimen>
        <dimen name="dp_256">256dp</dimen>
        <dimen name="dp_257">257dp</dimen>
        <dimen name="dp_258">258dp</dimen>
        <dimen name="dp_259">259dp</dimen>
        <dimen name="dp_260">260dp</dimen>
        <dimen name="dp_261">261dp</dimen>
        <dimen name="dp_262">262dp</dimen>
        <dimen name="dp_263">263dp</dimen>
        <dimen name="dp_264">264dp</dimen>
        <dimen name="dp_265">265dp</dimen>
        <dimen name="dp_266">266dp</dimen>
        <dimen name="dp_267">267dp</dimen>
        <dimen name="dp_268">268dp</dimen>
        <dimen name="dp_269">269dp</dimen>
        <dimen name="dp_270">270dp</dimen>
        <dimen name="dp_271">271dp</dimen>
        <dimen name="dp_272">272dp</dimen>
        <dimen name="dp_273">273dp</dimen>
        <dimen name="dp_274">274dp</dimen>
        <dimen name="dp_275">275dp</dimen>
        <dimen name="dp_276">276dp</dimen>
        <dimen name="dp_277">277dp</dimen>
        <dimen name="dp_278">278dp</dimen>
        <dimen name="dp_279">279dp</dimen>
        <dimen name="dp_280">280dp</dimen>
        <dimen name="dp_281">281dp</dimen>
        <dimen name="dp_282">282dp</dimen>
        <dimen name="dp_283">283dp</dimen>
        <dimen name="dp_284">284dp</dimen>
        <dimen name="dp_285">285dp</dimen>
        <dimen name="dp_286">286dp</dimen>
        <dimen name="dp_287">287dp</dimen>
        <dimen name="dp_288">288dp</dimen>
        <dimen name="dp_289">289dp</dimen>
        <dimen name="dp_290">290dp</dimen>
        <dimen name="dp_291">291dp</dimen>
        <dimen name="dp_292">292dp</dimen>
        <dimen name="dp_293">293dp</dimen>
        <dimen name="dp_294">294dp</dimen>
        <dimen name="dp_295">295dp</dimen>
        <dimen name="dp_296">296dp</dimen>
        <dimen name="dp_297">297dp</dimen>
        <dimen name="dp_298">298dp</dimen>
        <dimen name="dp_299">299dp</dimen>
        <dimen name="dp_300">300dp</dimen>
        <dimen name="dp_301">301dp</dimen>
        <dimen name="dp_302">302dp</dimen>
        <dimen name="dp_303">303dp</dimen>
        <dimen name="dp_304">304dp</dimen>
        <dimen name="dp_305">305dp</dimen>
        <dimen name="dp_306">306dp</dimen>
        <dimen name="dp_307">307dp</dimen>
        <dimen name="dp_308">308dp</dimen>
        <dimen name="dp_309">309dp</dimen>
        <dimen name="dp_310">310dp</dimen>
        <dimen name="dp_311">311dp</dimen>
        <dimen name="dp_312">312dp</dimen>
        <dimen name="dp_313">313dp</dimen>
        <dimen name="dp_314">314dp</dimen>
        <dimen name="dp_315">315dp</dimen>
        <dimen name="dp_316">316dp</dimen>
        <dimen name="dp_317">317dp</dimen>
        <dimen name="dp_318">318dp</dimen>
        <dimen name="dp_319">319dp</dimen>
        <dimen name="dp_320">320dp</dimen>
        <dimen name="dp_321">321dp</dimen>
        <dimen name="dp_322">322dp</dimen>
        <dimen name="dp_323">323dp</dimen>
        <dimen name="dp_324">324dp</dimen>
        <dimen name="dp_325">325dp</dimen>
        <dimen name="dp_326">326dp</dimen>
        <dimen name="dp_327">327dp</dimen>
        <dimen name="dp_328">328dp</dimen>
        <dimen name="dp_329">329dp</dimen>
        <dimen name="dp_330">330dp</dimen>
        <dimen name="dp_331">331dp</dimen>
        <dimen name="dp_332">332dp</dimen>
        <dimen name="dp_333">333dp</dimen>
        <dimen name="dp_334">334dp</dimen>
        <dimen name="dp_335">335dp</dimen>
        <dimen name="dp_336">336dp</dimen>
        <dimen name="dp_337">337dp</dimen>
        <dimen name="dp_338">338dp</dimen>
        <dimen name="dp_339">339dp</dimen>
        <dimen name="dp_340">340dp</dimen>
        <dimen name="dp_341">341dp</dimen>
        <dimen name="dp_342">342dp</dimen>
        <dimen name="dp_343">343dp</dimen>
        <dimen name="dp_344">344dp</dimen>
        <dimen name="dp_345">345dp</dimen>
        <dimen name="dp_346">346dp</dimen>
        <dimen name="dp_347">347dp</dimen>
        <dimen name="dp_348">348dp</dimen>
        <dimen name="dp_349">349dp</dimen>
        <dimen name="dp_350">350dp</dimen>
        <dimen name="dp_351">351dp</dimen>
        <dimen name="dp_352">352dp</dimen>
        <dimen name="dp_353">353dp</dimen>
        <dimen name="dp_354">354dp</dimen>
        <dimen name="dp_355">355dp</dimen>
        <dimen name="dp_356">356dp</dimen>
        <dimen name="dp_357">357dp</dimen>
        <dimen name="dp_358">358dp</dimen>
        <dimen name="dp_359">359dp</dimen>
        <dimen name="dp_360">360dp</dimen>
        <dimen name="dp_365">365dp</dimen>
        <dimen name="dp_370">370dp</dimen>
        <dimen name="dp_400">400dp</dimen>
        <dimen name="dp_410">410dp</dimen>
        <dimen name="dp_422">422dp</dimen>
        <dimen name="dp_472">472dp</dimen>
        <dimen name="dp_500">500dp</dimen>
        <dimen name="dp_600">600dp</dimen>
        <dimen name="dp_640">640dp</dimen>
        <dimen name="dp_720">720dp</dimen>
    
        <!--字体-->
        <dimen name="sp_6">6sp</dimen>
        <dimen name="sp_7">7sp</dimen>
        <dimen name="sp_8">8sp</dimen>
        <dimen name="sp_9">9sp</dimen>
        <dimen name="sp_10">10sp</dimen>
        <dimen name="sp_11">11sp</dimen>
        <dimen name="sp_12">12sp</dimen>
        <dimen name="sp_13">13sp</dimen>
        <dimen name="sp_14">14sp</dimen>
        <dimen name="sp_15">15sp</dimen>
        <dimen name="sp_16">16sp</dimen>
        <dimen name="sp_17">17sp</dimen>
        <dimen name="sp_18">18sp</dimen>
        <dimen name="sp_19">19sp</dimen>
        <dimen name="sp_20">20sp</dimen>
        <dimen name="sp_21">21sp</dimen>
        <dimen name="sp_22">22sp</dimen>
        <dimen name="sp_23">23sp</dimen>
        <dimen name="sp_24">24sp</dimen>
        <dimen name="sp_25">25sp</dimen>
        <dimen name="sp_26">26sp</dimen>
        <dimen name="sp_27">27sp</dimen>
        <dimen name="sp_28">28sp</dimen>
        <dimen name="sp_29">29sp</dimen>
        <dimen name="sp_30">30sp</dimen>
        <dimen name="sp_31">31sp</dimen>
        <dimen name="sp_32">32sp</dimen>
        <dimen name="sp_33">33sp</dimen>
        <dimen name="sp_34">34sp</dimen>
        <dimen name="sp_35">35sp</dimen>
        <dimen name="sp_36">36sp</dimen>
        <dimen name="sp_37">37sp</dimen>
        <dimen name="sp_38">38sp</dimen>
        <dimen name="sp_40">40sp</dimen>
        <dimen name="sp_42">42sp</dimen>
        <dimen name="sp_48">48sp</dimen>
    </resources>
    

    item布局有了,还要一个适配器,在com.llw.goodmusic包下新建一个adapter包,然后新建一个MusicListAdapter类。里面的代码如下:

    package com.llw.goodmusic.adapter;
    
    import androidx.annotation.Nullable;
    
    import com.chad.library.adapter.base.BaseQuickAdapter;
    import com.chad.library.adapter.base.BaseViewHolder;
    import com.llw.goodmusic.R;
    import com.llw.goodmusic.bean.Song;
    import com.llw.goodmusic.utils.DateTimeUtils;
    import java.util.List;
    
    /**
     * 音乐列表适配器
     *
     * @author llw
     */
    public class MusicListAdapter extends BaseQuickAdapter<Song, BaseViewHolder> {
    
        public MusicListAdapter(int layoutResId, @Nullable List<Song> data) {
            super(layoutResId, data);
    
        }
    
    
        @Override
        protected void convert(BaseViewHolder helper, Song item) {
            //给控件赋值
            int duration = item.duration;
            String time = DateTimeUtils.formatTime(duration);
    
            //歌曲名称
            helper.setText(R.id.tv_song_name, item.getSong().trim())
                    //歌手 - 专辑
                    .setText(R.id.tv_singer, item.getSinger() + " - " + item.getAlbum())
                    //歌曲时间
                    .setText(R.id.tv_duration_time, time)
                    //歌曲序号,因为getAdapterPosition得到的位置是从0开始,故而加1,
                    //是因为位置和1都是整数类型,直接赋值给TextView会报错,故而拼接了""
                    .setText(R.id.tv_position, helper.getAdapterPosition() + 1 + "");
    
            //给item添加点击事件,点击之后传递数据到播放页面或者在本页面进行音乐播放
            helper.addOnClickListener(R.id.item_music);
    
            //点击后改变文字颜色
            if (item.isCheck()) {
                helper.setTextColor(R.id.tv_position, mContext.getColor(R.color.gold_color))
                        .setTextColor(R.id.tv_song_name, mContext.getColor(R.color.gold_color))
                        .setTextColor(R.id.tv_singer, mContext.getColor(R.color.gold_color))
                        .setTextColor(R.id.tv_duration_time, mContext.getColor(R.color.gold_color));
            } else {
                helper.setTextColor(R.id.tv_position, mContext.getColor(R.color.white))
                        .setTextColor(R.id.tv_song_name, mContext.getColor(R.color.white))
                        .setTextColor(R.id.tv_singer, mContext.getColor(R.color.white))
                        .setTextColor(R.id.tv_duration_time, mContext.getColor(R.color.white));
            }
    
        }
    
        /**
         * 刷新数据
         */
        public void changeState() {
            notifyDataSetChanged();
        }
    }
    
    

    上面的代码,除了基本的数据填充之外也没有什么好说,只有一个点击歌曲时更改文字颜色,类似与一般的音乐APP歌曲的效果。当在Activity点击item时,调用changeState方法刷新数据。
    好了,一切的准备工作都做完了。看起来这个功能好像没啥东西,但是要想的细节是很多的。下面回到LocalMusicActivity。
    定义一些需要的变量

    	private Toolbar toolbar;
        /**
         * 歌曲列表
         */
        private RecyclerView rvMusic;
        /**
         * 扫描歌曲布局
         */
        private LinearLayout layScanMusic;
        /**
         * 歌曲适配器
         */
        private MusicListAdapter mAdapter;
        /**
         * 歌曲列表
         */
        private List<Song> mList = new ArrayList<>();
    
        /**
         * 上一次点击的位置
         */
        private int oldPosition = -1;
        
    	/**
         * 初始化控件级页面的业务逻辑
         */
        private void initView() {
            ActivityLocalMusicBinding binding = DataBindingUtil.setContentView(context, R.layout.activity_local_music);
            toolbar = binding.toolbar;
            rvMusic = binding.rvMusic;
            layScanMusic = binding.layScanMusic;
            Back(toolbar);
    
            //当进入页面时发现有缓存数据时,则隐藏扫描布局,直接获取本地数据。
            if (SPUtils.getBoolean(Constant.LOCAL_MUSIC_DATA, false, context)) {
                //省去一个点击扫描的步骤
                layScanMusic.setVisibility(View.GONE);
                permissionsRequest();
            }
        }
    

    新建一个方法,在权限通过时调用
    在这里插入图片描述
    方法如下:

    	/**
         * 获取音乐列表
         */
        private void getMusicList() {
    
            //清除列表数据
            mList.clear();
            //将扫描到的音乐赋值给音乐列表
            mList = MusicUtils.getMusicData(this);
    
            if (mList != null && mList.size() > 0) {
                //是否有缓存歌曲
                SPUtils.putBoolean(Constant.LOCAL_MUSIC_DATA, true, context);
                layScanMusic.setVisibility(View.GONE);
                //显示本地音乐
                showLocalMusicData();
            } else {
                show("兄嘚,你是一无所有啊~");
            }
    
        }
    

    然后再看showLocalMusicData方法:

    	/**
         * 显示本地音乐数据
         */
        private void showLocalMusicData() {
            //指定适配器的布局和数据源
            mAdapter = new MusicListAdapter(R.layout.item_music_rv_list, mList);
            //线性布局管理器,可以设置横向还是纵向,RecyclerView默认是纵向的,所以不用处理,如果不需要设置方向,代码还可以更加的精简如下
            rvMusic.setLayoutManager(new LinearLayoutManager(this));
            //设置适配器
            rvMusic.setAdapter(mAdapter);
    
            //item的点击事件
            mAdapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() {
                @Override
                public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
                    if (view.getId() == R.id.item_music) {
    
                        if (oldPosition == -1) {
                            //未点击过 第一次点击
                            oldPosition = position;
                            mList.get(position).setCheck(true);
                        } else {
                            //大于 1次
                            if (oldPosition != position) {
                                mList.get(oldPosition).setCheck(false);
                                mList.get(position).setCheck(true);
                                //重新设置位置,当下一次点击时position又会和oldPosition不一样
                                oldPosition = position;
                            }
                        }
                        mAdapter.changeState();
                    }
                }
            });
        }
    

      这里通过点击的位置进行控制歌曲的状态。OK,代码就写完了。这里我再说一下业务逻辑,当第一次点击扫描按钮时,会请求文件读写取权限,我只放了写入的权限,因为文件操作的权限是在一个权限组里,通过一个就是通过一组,拿到权限之后获取工具类扫描到的歌曲数据,有数据则显示,而对于点击位置的控制,则是通过一个全局变量来操作,oldPosition初始值为-1,当第一次点击时,加入点击了第三项,那么oldPosition就是为2。这个时候将position对应的数据的check设置为true。然后调用mAdapter.changeState();刷新数据。然后可以点击第三项,这个时候oldPosition是不等于position的。

    							mList.get(oldPosition).setCheck(false);
                                mList.get(position).setCheck(true);
                                //重新设置位置,当下一次点击时position又会和oldPosition不一样
                                oldPosition = position;
    

    所以把oldPosition对应数据取消选中,而把position对应数据进行选中,之后把 oldPosition = position;最后退出判断之后又会刷新数据。
    下面来运行一下看一下效果。
    在这里插入图片描述

    结语

      目前才刚开始写,这一篇写音乐扫描和获取,饭要一口一口吃,功能要一个一个来写,感兴趣的也可以看一下。有哪里不明白的评论告诉我,我会及时回复,谢谢你的阅读,做一个有内容的作者。
    源码地址:Good Music

    展开全文
  • iPhone导出网易云音乐本地音乐

    千次阅读 2020-01-17 00:37:51
    旧手机通过 iTunes 备份电脑上,再用备份恢复新手机。恢复以后发现网易云音乐本地音乐并没有包含在备份文件中,导致新手机网易云音乐里空空如也。此时萌生了导出旧手机中网易云音乐本地音乐的想法。 方案...

    目录

    前提

    方案

    环境

    步骤

    越狱

    导出


    前提

    换手机。先把旧手机通过 iTunes 备份到电脑上,再用备份恢复新手机。恢复以后发现网易云音乐的本地音乐并没有包含在备份文件中,导致新手机网易云音乐里空空如也。此时萌生了导出旧手机中网易云音乐本地音乐的想法。

     

    方案

    ①  通过 Cydia impactor 和 FilzaEscaped 完成 iPhone 在未越狱情况下对系统文件的访问。

         参考博文:iPhone网易云音乐app的离线音乐导出到电脑

         失败原因:只支持 ios12 以下,我的系统已经更新到了 ios13.3 。

    ②  通过支持 ios13.3 的最新越狱工具 checkra1n 越狱,完成对系统文件的访问。

          checkra1n 支持 iPhone 5s – iPhone X 的设备、iOS 12.3 以上系统的越狱。

          由于 checkra1n 目前只支持 MacOS ,所以在这里有三个子方案。

          1. 通过 iMac 或 MacBook 越狱(最佳选择)

              失败原因:没有 Mac 系统的电脑。

          2. 通过 VM Ware 安装 MacOS

              失败原因:未知,会在 checkra1n 运行过程中出现 -31 错误,应该是因为不能实现usb穿透。

          3. 通过 ubuntu 下的 KVM 虚拟机运行 MacOS(最终成功)

              参考帖子:使用黑苹果checkra1n越狱安全稳妥的方法

              利用帮助 checkra1n 在 Windows 和 Linux 下运行的 ra1nstorm 完成。

              下面给出该方案的步骤。

     

    环境

    手机型号:iPhone 6s

    系统版本:ios13.3

    电脑系统:Win10

     

    步骤

    越狱

    ①  在 BIOS 中启用 CPU 虚拟化技术

          不同电脑开启方法略有不同,但应该都是在BIOS里开启。

    ②  利用 DiskGenius 分出 100g 左右的空闲空间后格式化为 NTFS 格式

          实际最后没有用到 100g ,但是我为了稳妥还是分了这么多,用完反正要删除。

    ③  利用 UltraISO 制作 Xubuntu 的启动盘

         镜像直接从 Xubuntu 官网 下载即可。我用的是 Xubuntu 18.04 LTS 64位镜像。

    ④  将 Xubuntu 安装在空闲空间

          u 盘引导启动并安装,注意分区 /home 下要预留超过 40g 的空间,否则在 ra1nstorm 运行过程中会报错。

    ⑤  启动后在终端执行 sudo apt-get update 和 sudo apt-get upgrade

    ⑥  从 ra1nstorm Github 下载最新版的 ra1nstorm.run 并保存在 /home/用户名 目录下

    ⑦  终端执行 sudo bash ra1nstorm.run 进入安装程序

    ⑧  根据提示进行安装

         1. 可能会在安装 qemu 时报错,只要在终端执行 sudo apt-get install qemu ,手动安装 qemu 后再次进入安装程序即可。

         2. 安装完成后会打开虚拟机,键盘左右选择 “Boot macOS Install from macOS Base System” 。

         3.  进入 MacOS 后选择 “重新安装Mac副本” ,注意观察 ra1nstorm 的提示进行安装即可。

         4.  MacOS 安装完成后系统会重启。

    ⑨  终端执行 sudo bash ra1nstorm.run 进入安装程序

         此时菜单已变更,选择 “Boot macOS from 分区名” 即可进入 MacOS 。

    ⑩  在 MacOS 中进入 checkra1n官网 下载工具并完成越狱

          1. 注意这里需要插网线,MacOS才能联网。

          2. iPhone 桌面上出现 checkra1n 图标,说明越狱成功,打开 checkra1n 安装 Cydia 。

          3. 由于 checkra1n 是不完美越狱,所以在 iPhone 重启后会丢失越狱状态,最好插上电源保持电量充足。

     

    导出

    ①  在 iPhone 的 Cydia 里安装 OpenSSH

    ②  下载 WinSCP

    ③  在 WinSCP 中新建连接

          主机名:手机的 IP

          端口号:22

          用户名:root

          密码:alpine

    ④  找到网易云音乐的数据文件夹

          1. 访问 /var/mobile/Containers/Data/Application/

          2. 由于不同手机网易云音乐文件夹的名字可能不一样,比如我的就跟网上查到的 /var/mobile/Containers/Data/Application/01C984A6-DF5E-494E-9946-44F39138A923/ 不一样,所以可以在这里搜索 *.mp3 找到自己手机里网易云音乐的文件夹。

          3. 本地音乐在网易云音乐文件夹下 /Documents/UserData/Download/done/ 中,注意在 WinSCP 中直接下载可能会报错,可以先将所有歌曲移动到可识别目录下,如 /var/mobile/Media/ 就可以,这样就可以通过 iTools 等软件访问可识别目录并导出歌曲。

     

    至此就完成了网易云音乐本地文件的导出。

    越狱 3 分钟,准备越狱 2546843168451345315465146 分钟。

    展开全文
  • 为了向大家证明小编不是耍流氓,是耍无赖,我决定教大家直接网易云音乐歌手的热门歌曲全部免费下载下来。除了已经下架不在网易数据库的,其他的都能全部下载下来,咳咳,你懂的。给几张图,自己体会。爬取结果:...

    本文是承接前两文章而来,前两篇文章我们收集了歌手信息和歌词,可是光有歌手信息和歌词没有歌曲怎么行,没有歌曲怎么知道音调,这让人怎么学?怎么听?这不耍流氓嘛?为了向大家证明小编不是耍流氓,是耍无赖,我决定教大家直接把网易云音乐歌手的热门歌曲全部免费下载下来。除了已经下架不在网易数据库的,其他的都能全部下载下来,咳咳,你懂的。给几张图,自己体会。

    爬取结果:

    直接下载:

    但是个别几首歌如果已经下架的话,可以下载下来,但是听不了的,下架的歌曲毕竟是少数。

    这次的代码很简单,因为上 2 篇文章已经把大部分前期工作做完了,还没上车的同学请戳以下两篇文章:

    Python 爬虫获取网易云音乐歌手信息

    Python 爬虫获取网易云音乐歌手歌词

    前面没弄懂的也没关系,文章底部会把前面两次的源码和爬虫结果文件的获取方式给出。

    导包

    之前的代码完成后,我们把它放在同一个目录下是可以直接导入并调用其方法的。务必要放在同一文件夹下面,这样调用才不会报错。本次我需要调用上次获取歌词的lyrics163.py 文件,因为里面的 get_top50() 方法返回的信息有本次需要的歌曲 id。

    用网页上显示的链接直接下载歌曲不可行。众里寻他千百度,终于被我找到了网易提供的外部的歌曲链接,输入相应歌曲的 id 拼接获取歌曲外部可下载的链接。

    songurl = 'http://music.163.com/song/media/outer/url?id={}.mp3'.format(songid)

    下载歌曲

    接下来就简单了,定义一个下载歌曲的函数就可以下载歌曲了。用 urlretrieve 下载音频文件,调用时入参填歌曲 url 和存放路径即可。

    主函数

    主函数,输入歌手对应的 id ,直接调用之前的保存歌词源码 lyrics163.py 里的方法获取歌曲 id,再调用上面的方法下载歌曲即可。保存路径提前建好,比如我在 E 盘新建了「song」目录,下载的歌曲都会保存在这个目录下。

    这样,你想听哪个歌手的歌曲,输入歌手 id,运行此代码,分分钟 热门歌曲下载到本地。是不是很轻松?

    是不是觉得很爽?是不是很想试试,快来动手吧!好的东西应该免费分享给大家,快举起你那天使般的小手,点波转发吧!当然,土豪就请随意咯!

    写在最后:

    如果大家在学习Python的路上,或者打算学习Python需要学习资料,可以在评论区留言1314,小编将免费赠送大家学习资料喔!

    本文来自网络,如有侵权,请联系小编删除!

    展开全文
  • python爬虫--下载酷我音乐

    千次阅读 2018-06-21 11:25:40
    本次练习的主要内容:通过python爬虫,破解酷我音乐的api,下载音乐文件到本地。(一)项目概况1. 这里酷我音乐的首页:2. 点击左上角的榜单,进去之后再点击具体歌名,跳转到音乐播放页面,可以在线听音乐:3. 本次...
  • 网易云会员音乐NCM格式在线转为MP3格式 进入网址:http://ncm.worthsee.com/点击选择文件开始转换 点击选择文件找到要转换的.ncm文件,点击打开即可,可以多选 然后下载全部即可,虽然有的会转换为.flac,但并不...
  • scrapy 爬取酷狗T500音乐,并把音乐下载到本地,其中下载的音乐信息保存到mongoDB
  • 让用户输入要搜索的音乐名,然后所有的音乐以及每一个音乐对应的信息展示给用户。再询问用户要不要下载任何音乐,如果要,则让用户输入音乐对应的id号来下载(支持批量下载)。 找出思路 首先,在获取多首歌曲的...
  • 那么,针对这个问题,IT狼~早就准备好了,哈哈,带来一个小技巧,分享给大家怎么通过缓存的歌曲,转化成本地歌曲,以便于随时离线听以及保存。这里以酷我音乐为例。 1.原理 (俗话说得好,授人以鱼不如授人以渔。这...
  • 网易云音乐缓存文件解密

    千次阅读 2021-11-30 20:58:15
    一、随便播放一首歌曲,使其产生缓存文件,并在下载设置中找到缓存目录 ...点击OK,保存文件即可,之后就可以点开我们解密后的MP3文件,使用任意播放器均可(该方法对VIP歌曲同样适用,大家可以自行尝试操作) ...
  • 同时支持在线音乐本地音乐的播放,是国内内容最丰富的音乐平台。其独特的音乐搜索和推荐功能,让您可以尽情地享受最流行,最火爆的音乐。 2. 选择理由 QQ音乐作为老牌音乐产品,根植于PC端,后发力于移动端,...
  • python 使用 selenium 爬取酷狗音乐飙升榜(100)包括歌曲播放地址 音乐名 作者 以及音乐资源url地址
  • Mac平台上好用的音乐播放器有什么推荐?想要最新最热的音乐排行榜、歌单...一、QQ音乐 for Mac (免费绿钻vip) v9.9.9.3 特别版 QQ音乐让你在Mac平台获得最佳的音乐体验。最全的高品质正版音乐曲库,任你免费试听下...
  • 现在网易云音乐版权问题多,有的干脆没有,有的需要购买vip,歌单能听的越来越少,于是想要曲库放NAS上,为了方便保存与共享。 但在网易云客户端中,将路径指向NAS中的路径时,出现了问题。网易云音乐识别出这是...
  • 今天的主题,就是给大伙介绍个免费下载网易云音乐的收费音乐(其他平台也适用) 。简单实用,基本不需要什么计算机编程基础,人人都可学会! 废话不多说,直接进入主题! 先用谷歌浏览器打开网易云音乐 ...
  • QQ音乐付费格式转换

    万次阅读 多人点赞 2019-06-25 09:40:29
    怎样把QQ音乐的qmc3格式音频转化mp3呢? 为什么要转呢?具体原因你也明白,嘿嘿 ~ * 1. 网页版(单个) link:http://moresound.tk/music/qmc/ 这个网站好像给过期了 2. 本地版(批量win) link:...
  • 由于各种音乐版权的不可抗因素, 很多优质音乐只能在线试听却不能下载。 大部分人想要下载只能去网上搜各种云盘, 各种资源, 求分享。花了很多时间、精力也未必能下载的。 如何简单地通过网页下载付费音乐? 注...
  • 相信很多网友都有上传QQ空间照片的喜好,我就是其中一个,拍了一张漂亮的PP,恨不得马上传空间,炫耀一番。上传的照片日积月累,越来越多。平常要一张张的观看照片挺费时。最近学了一个新招,可以使用狸窝照片制作...
  • 4、python分析酷我音乐

    千次阅读 多人点赞 2021-02-26 23:38:07
    4、python抓取vip音乐 1、环境依赖: 需要安装requests和jsonpath这两个模块 2、步骤: (1)首先,进入酷我音乐官网 (2)鼠标右键点击检查,选择notework 这一栏中的Media 是筛选音频文件、视频文件的,点击播放...
  • 功能概述让用户输入要搜索的音乐名,然后所有的音乐以及每一个音乐对应的信息展示给用户。再询问用户要不要下载任何音乐,如果要,则让用户输入音乐对应的id号来下载(支持批量下载)。找出思路首...
  • 爬虫入门经典(二十三) | fiddler抓包爬取QQ音乐

    万次阅读 多人点赞 2020-11-26 13:49:27
    作为一名互联网行业的小白,博主写博客一方面是为了记录自己的学习过程,另一方面是总结自己所犯的错误希望能够帮助很多和自己一样处于起步阶段的萌新。但由于水平有限,博客中难免会有一些错误出现,有纰漏之处...
  • python爬去音乐

    2020-11-29 21:02:58
    广告关闭腾讯云11.11云上......entry 输入控件:用于显示简单的文本内容label 标签控件listbox 列表框控件,显示字符串返回给用户text 文本控件,显示多行文本软件目标开发一款音乐下载器通过爬虫获取音乐解析网上...
  • 基本就是开通了永久VIP+高清包月的所有本地功能。 麦克疯缓存的MV是加密过的不能直接播放,使用本工具可以方便播放时解密过的文件提取出来。 建议配合我上次发布的破解版使用,可以提取高清MV,效果更佳。。。 MV...
  • 最近在学习go,学习一门语言最好的方式就是实践,之前学习python也是从爬虫入手,现在使用go语言写一个网易云音乐的爬虫,下面会简单介绍开发的过程,代码是初学者的水平,欢迎吐槽。 本项目github地址...
  • Python3运用requests包爬取QQ音乐指定歌手歌曲

    千次阅读 多人点赞 2019-09-13 18:15:59
    Python3应用requests包...这个聚焦爬虫可以用来爬取QQ音乐web端指定歌手的音乐(客户端需要vip才能听的也可以爬),大家喜欢的可以多点赞(手动狗头)。接下来上代码和讲解: 这个爬虫采用了面向对象的思想,运用...
  • 音乐搜索器-多站合一 漂亮的小警报..???? 通知是一种在新数据可用于该应用时通知用户的方法,即使该应用未在前台运行也是如此。 例如,消息收发应用程序可能会在新消息到达时通知用户,而日历应用程序可能会通知...
  • Android逆向之旅---Android手机端破解神器MT的内购VIP功能破解教程
  • 免费下载收费音乐

    万次阅读 2018-08-15 16:13:47
    示例:网易云音乐(其他音乐也是同等方法,相如QQ音乐等需要转码) 1、用浏览器打开网易云音乐https://music.163.com/ 2、然后打开想下载的收费音乐,直接按 F12 键,点击 控制台 的“Network”,然后选择“Media...
  • 今天要介绍的是在安卓手机上解决视频加背景音乐怎么弄的问题哦~还可以一键识别添加的背景音乐的歌词,并添加该歌词视频中哦(暂时仅支持国语歌词)~不是视频音乐怎么制作以及ppt怎么放背景音乐等问题哦,而是选择...
  • 首先在浏览器在打开网易云音乐的网页版,并点进一个歌单。2.在浏览器的开发者工具审查该页面的元素(一般按f12可以弹出该工具),选择Network,之后选择doc可以简便地找到我们需要的元素。注:以下两步第3,第4步主要...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 575
精华内容 230
热门标签
关键字:

怎样把vip音乐保存到本地