如何从ios酷我音乐盒中导出已下载的音乐文件

本文所涉及内容用于技术学习,请勿用于不正当用途,否则后果自负。
酷我音乐ios版下载的音乐文件,通过同步助手等软件查看时,发现音乐文件都是一串数字命名。通过网上查找和自己尝试,发现那些文件都是音频文件改了文件名而已。只要修改回文件名,就能和正常的音乐一样播放了。
参考网址:
http://blog.sina.com.cn/s/blog_4d5428240101enzu.html

在网上找到了一个软件,也就是上面参考网址中的软件,但是使用的时候出现了问题,提示subscript out of range,程序不能继续执行。于是就决定自己用Java写一个来处理。
首先从手机复制出cloud.db数据库文件,为SQLite数据库文件。用SQLite Database Browser打开,看到里面和音乐关系比较密切的主要有三个table,playlistsInfo中保存着播放列表信息,字段title为列表名称,字段id为列表id。playlistMusics保存了音乐和播放列表的对应关系,字段title、artist等为音乐信息,rid为音乐资源id,字段playlist_id对应了所属播放列表id。musicResource中是音乐信息和文件对应关系,字段file为对应的文件名,format为文件格式,rid为音乐资源id。
 
 

于是程序的工作流程是这样的:
1、首先从musicResource逐一读取每首音乐的rid;
2、通过rid在playlistMusics中查找playlist_id,可能找不到,也可能不止一个,因为同一首音乐可能在多个列表中,这里简单的取最大的playlist_id,通常应该是相对比较新的播放列表;
3、然后在playlistsInfo中找到playlist_id对应的播放列表名,作为目标音乐的子文件夹;
4、最后把源文件重命名为“歌手名 - 歌曲名.扩展名”,并移动到目标文件夹即可。
为方便交流学习,这里提供本程序源码。
  1. import java.io.File;
  2. import java.sql.Connection;
  3. import java.sql.DriverManager;
  4. import java.sql.ResultSet;
  5. import java.sql.Statement;
  6. import java.util.ArrayList;
  7. import java.util.List;
  8. public class Test {
  9. /**
  10. * 存储播放列表的数据结构
  11. *
  12. * @author jzj
  13. */
  14. static class PlayList {
  15. int id;
  16. String name;
  17. public PlayList(String name, int id) {
  18. this.name = name;
  19. this.id = id;
  20. }
  21. }
  22. // 数据库完整路径
  23. static final String db_path = "G:\\IOS\\cloud.db";
  24. // 源文件夹
  25. static final String src_dir = "G:\\IOS\\Music\\";
  26. // 目标文件夹
  27. static final String dst_dir = "G:\\IOS\\Music1\\";
  28. public static void main(String[] args) throws Exception {
  29. Class.forName("org.sqlite.JDBC");
  30. Connection conn = DriverManager.getConnection("jdbc:sqlite:" + db_path);
  31. Statement stat1 = conn.createStatement();
  32. Statement stat2 = conn.createStatement();
  33. // 读取播放列表
  34. List<PlayList> lists = new ArrayList<Test.PlayList>();
  35. ResultSet rs_list = stat1.executeQuery("select * from playlistsInfo;");
  36. while (rs_list.next()) {
  37. final int id = rs_list.getInt("id");
  38. final String name = rs_list.getString("title");
  39. switch (name) {
  40. // 忽略这几个列表
  41. case "本地歌曲":
  42. case "默认列表":
  43. case "最近播放":
  44. case "我的电台":
  45. break;
  46. case "我喜欢听":
  47. default:
  48. lists.add(new PlayList(name, id));
  49. }
  50. }
  51. // 读取音乐信息
  52. ResultSet rs_res = stat1.executeQuery("select * from musicResource;");
  53. while (rs_res.next()) {
  54. // 源文件路径
  55. String fname = rs_res.getString("file");
  56. if (fname == null || fname.length() == 0) // 如果file字段为空则跳过
  57. continue;
  58. String src_path = src_dir + fname;
  59. File src = new File(src_path);
  60. if (!src.exists()) // 如果源文件不存在则跳过
  61. continue;
  62. // 获取音乐rid
  63. int rid = rs_res.getInt("rid");
  64. // 查找该音乐所在播放列表id, 如果没有找到则为-1
  65. ResultSet rs_pl = stat2.executeQuery(new StringBuilder(
  66. "select playlist_id from playlistMusics where rid=")
  67. .append(rid).append(';').toString());
  68. int playlist_id = -1;
  69. while (rs_pl.next()) { // 默认将一首歌放在编号最大的播放列表中(也就是最新创建的列表)
  70. int p_id = rs_pl.getInt("playlist_id");
  71. if (p_id > playlist_id)
  72. playlist_id = p_id;
  73. }
  74. rs_pl.close();
  75. // 目标文件夹路径
  76. StringBuilder b2 = new StringBuilder(dst_dir);
  77. if (playlist_id >= 0) {
  78. String playlist_name = getPlaylist(lists, playlist_id);
  79. if (playlist_name != null) {
  80. b2.append(playlist_name).append('\\');
  81. }
  82. }
  83. String dir = b2.toString();
  84. new File(dir).mkdirs();
  85. // 目标文件名: "艺术家 - 歌曲名.扩展名"
  86. StringBuilder b3 = new StringBuilder();
  87. b3.append(rs_res.getString("artist")).append(" - ")
  88. .append(rs_res.getString("title")).append('.')
  89. .append(rs_res.getString("format"));
  90. String dst_path = dir + b3.toString();
  91. // 移动和重命名
  92. File dst = new File(dst_path);
  93. src.renameTo(dst);
  94. // 输出信息
  95. System.out.println(new StringBuilder(src_path).append(" ---> ")
  96. .append(dst_path));
  97. }
  98. rs_res.close();
  99. conn.close();
  100. }
  101. static String getPlaylist(List<PlayList> lists, int playlist_id) {
  102. for (PlayList pl : lists) {
  103. if (pl.id == playlist_id)
  104. return pl.name;
  105. }
  106. return null;
  107. }
  108. }
由于涉及数据库操作,需要在Java工程中添加数据库支持包,可参看这篇文章 http://ttitfly.iteye.com/blog/143934
使用nested包:sqlitejdbc-v037-nested.jar
将音频文件全部复制出来,放到程序中src_dir所指定的目录,数据库文件cloud.db保存在db_path指定的位置,设置好目标文件夹dst_dir,执行程序即可整流导出的音频文件,实测700多首音乐,只需不到一分钟时间即可完成重命名和移动工作。
完整工程可在此下载:
http://pan.baidu.com/s/1hGNT0

转载于:https://www.cnblogs.com/jzj1993/p/3859461.html

如何从ipad(iphone)的酷我音乐盒中导出已下载的音乐文件相关推荐

  1. 如何从ios酷我音乐盒中导出已下载的音乐文件(使用Java编程实现)

    本工具已经编写了第二版,为不了解编程的读者提供了可以直接使用的软件,请移步这里阅读和使用 http://blog.csdn.net/jzj1993/article/details/44459983 本 ...

  2. 怎么从Chrome浏览器中导出扩展程序为crx文件?

    在chrome浏览器中安装好一些我们需要的chrome扩展程序后,有一天如果浏览器需求卸载后重新安装,但是我们这些插件又不好备份,当然用户可以始终在我们chrome插件网( http://www.cn ...

  3. Vue中实现图片下载到本地功能和导出(下载)excel文件功能:

    一.实现图片下载到本地功能 需求: 将勾选的列表项的id传给后台,让后台处理并下载对应的图片 1. 后台接口: 下载图片zip: GET /download 请求数据类型 application/x- ...

  4. Asp.NET中如何一次性下载多个文件

    在ASP.NET中,我们可以很方便的下载单个文件,当需要一次性下载多个文件的时候,如果提示用户一次一次保存的话,会导致用户体验特别的不好.我这里找到一种比较合理的解决方案,就是先把要下载的所有文件打包 ...

  5. vue移动端h5中a标签下载/预览文件

    需求:项目分PC端和移动端,PC端(react)以实现列表页附件下载,现需同步移动端(vue)h5页面在原有的列表页中增加一行查看(下载)附件. 只写结构,暂不考虑其他,增加附件行的代码如下: < ...

  6. iPhone用户干货:袋鼠下载,如何导出已下载的视频到其他播放器?

    今天要给大家带来相关教程,袋鼠下载一键导出转存,视频永久保留. 要达到袋鼠下载器里面的视频一键导出转存,使视频永久保留的目的,我们需要使用一款叫袋鼠播放器的软件,这也是袋鼠的又一大神器,这款软件能在A ...

  7. 使用MediaPlayer播放USB中读取到的MP3音乐文件,遇到java.io.FileNotFoundException异常总结

    项目背景: 多媒体USB音乐,底层调用MediaPlayer来播放U盘中读取的歌曲,由于最初版本将一首MP3歌曲甜蜜蜜写到了AS的raw目录,直接本地播放,做了一首假数据: 即: //临时代码,写死歌 ...

  8. 全名k歌导出已发布的音乐方法

    1.      登录网页版的全民k歌,进入自己的个人主页 2.      选择一个自己的作品,比如下面的"依然爱你" 3.点击作品,我们可以看到已经播放音乐了. 4.此刻按下F12 ...

  9. java.util.zip包 OutputStream ZipOutputStream以压缩包的方式导出或下载多个文件,比如图片,文档,Excel表格等

    目录 前言 逻辑流程 代码 请求接口 压缩文件方法 关闭文件流 前言 接到个需求,从数据库查询出多个用户,每个用户都会有头像,以压缩包的方式下载这些用户的头像,这里用到了java.util.zip包下 ...

最新文章

  1. LeetCode简单题之自除数
  2. POPUP_GET_VALUES_DB_CHECKED’
  3. shop--10.店铺详情(后台+前端类似于shoplist)
  4. mysql查询活跃连接,mysql – 使用大量可能的连接进行查询的最佳方法
  5. set python_使用dict和set
  6. Anaconda3使用过程中遇到的问题
  7. ionic入门教程第五课-举例子说明异步回调$q及$q在项目中的用法
  8. 基于seq2seq模型的chatbot对话系统的tensorflow实现
  9. 读《An Adaptable and Extensible Geometry Kernel》
  10. 通过蚁剑,利用eval与assert,登录目标网站
  11. 《图像处理、分析与机器视觉》(第4版)阅读笔记——第五章 图像预处理
  12. 自媒体推广有哪些好处?
  13. gis可达性分析步骤_基于三维GIS技术的公路交通数字孪生系统
  14. 关于在使用迅雷下载的时候,C盘一下爆满的问题
  15. linux 中文字体美化,美化ubuntu字体
  16. Springboot毕设项目医疗云胶片管理系统nem7xjava+VUE+Mybatis+Maven+Mysql+sprnig)
  17. 20+ Prompt工具网站汇总;我用AI工具开了一家「无人公司」;如何10分钟上线一个AI导航网站;第一部AIGC中英双语图文辞典 | ShowMeAI日报
  18. 计算机应用基础任务化教程135,在PowerPoint 2010中SmartArt图形的制作及技巧.doc
  19. 单极化天线和双极化天线的区别
  20. orcad capture学习笔记---1.绘制原理图封装

热门文章

  1. iText in Action 2nd3.1节(Introducing the concept of direct content)读书笔记
  2. Windeployqt 打包,缺少DLL 的原因分析,解决方法
  3. 软件测试获取动态验证码并填充selenium python
  4. PowerBasic版上海期货交易接口技术文档
  5. 反编译9.png图片还原
  6. JavaScript 击鼓传花的游戏 使用数据结构---队列来实现击鼓传花
  7. 非因解读 | 利用DSP技术绘制非小细胞肺癌(NSCLC)肿瘤微环境图谱
  8. COMSOL基于方程建模
  9. 纷菲幻剑录 之 十年一剑
  10. Visual Novel Maker v1.0.1074 视觉小说游戏制作软件